Здесь приведены тексты процедур для работы с
| Часть файла | Длина в байтах |
|---|---|
| Заголовок | 128 |
| Упакованная информация о пикселах изображения | переменная |
| Тип палитры | 1 |
| Палитра | 768 |
Заголовок файла содержит информацию о размерах изображения, количестве цветов и т.п. В процедуре чтения (READ_PCX) заголовок игнорируется, так как эти данные предполагаются уже известными. В процедуре записи (MAKE_PCX) заголовок записывается всегда один и тот же.
Информация о пикселах изображения хранится в упакованном виде. При
упаковке последовательность одинаковых байтов заменяется на два байта: счётчик
и оригинал. Чтобы можно было распознавать
Тип палитры #0A, если значения байтов палитры находятся в диапазоне 063, и #0C, если в диапазоне 0255. В процедуре чтения тип палитры игнорируется, а в процедуре записи записывается #0C.
Палитра в ней содержится информация о компонентах R, G, B каждого из 256 цветов изображения. В процедуре чтения палитра игнорируется, а в процедуре записи записывается последовательность байтов (0,0,0, 1,1,1, , 255,255,255).
Исходя из вышесказанного, можно определить максимальную длину
файла: 2 байта на пиксел это 256*192*2=#18000, ещё #80
байтов заголовок, 1 байт тип палитры и #300
байтов сама палитра, итого #18381 байт. Но в
Итак, тексты процедур.
| 1. | READ_PCX чтение изображения из
|
| Вход: | имя и расширение файла указано в FILENAME, номера банков памяти в N_BANK. |
Выход: | A=1 OK, A=0 файл не найден. |
;Структуры данных:
BUFER EQU #7000 ;256-байтный буфер (адрес кратен 256!).
;Пошла сама процедура:
ORG #6000
READ_PCX LD HL,BUFER
LD (GET_B_0),HL
LD HL,N_BANK
LD (PUT_B_1),HL
LD HL,#C000
LD (PUT_B_2),HL
;Ищем файл:
LD HL,FILENAME
LD C,#13
CALL #3D13
LD C,#0A
CALL #3D13
LD A,C
INC A
RET Z ;Нет такого файла.
DEC A
LD C,8 ;Читаем
CALL #3D13 ;дескриптор.
;Определяем трек/секторный адрес начала
;файла:
LD HL,(#5CEB)
LD (GET_B_1),HL
;Пропускаем первые 128 байтов файла -
;это заголовок.
LD B,128
M1 CALL GET_B
DJNZ M1
LD HL,#C000 ;Кол-во pix.
;Главный цикл:
M3 CALL GET_B ;Читаем байт.
;Если это байт-счётчик, то два его
;старших бита установлены в 1, а в
;младших 6 битах - количество
;повторений.
LD B,1
LD C,A
CPL
AND %11000000
LD A,C
JR NZ,M2
;Повторяем следующий байт указанное
;количество раз:
LD A,%00111111
AND C
LD B,A
CALL GET_B
M2 CALL PUT_B
DEC HL
DJNZ M2
LD A,H ;Все #C000 пикселов?
OR L
JR NZ,M3
INC A ;A:=1.
RET
;Имя файла:
FILENAME DB "picture pcx"
;Номера используемых банков памяти:
N_BANK DB #10,#11,#13
;---------------------------------------
;Процедура GET_B - чтение байта из
;файла.
GET_B PUSH HL
PUSH BC
LD HL,0 ;Адрес в буфере.
GET_B_0 EQU $-2
LD A,L
AND A
JR NZ,GET_B_3
;Надо прочитать сектор файла:
PUSH HL
LD B,1
LD DE,0
GET_B_1 EQU $-2
PUSH DE
LD HL,BUFER
LD C,5
CALL #3D13
;Увеличиваем трек/секторный адрес:
POP DE
INC E
BIT 4,E
JR Z,GET_B_2
LD E,0
INC D
GET_B_2 LD (GET_B_1),DE
POP HL
;Читаем байт из буфера:
GET_B_3 LD A,(HL)
INC L
LD (GET_B_0),HL
POP BC
POP HL
RET
;---------------------------------------
;Процедура PUT_B - помещение информации
;об очередном пикселе в память.
PUT_B PUSH AF
PUSH HL
PUSH AF
PUSH BC
LD HL,0
PUT_B_1 EQU $-2
LD A,(HL) ;N банка.
LD BC,#7FFD
OUT (C),A
POP BC
POP AF
LD HL,0 ;Адрес.
PUT_B_2 EQU $-2
LD (HL),A
INC HL ;Увелич. адреса.
LD A,H
OR L
JR NZ,PUT_B_3
LD HL,(PUT_B_1) ;Переход к
INC HL ;следующему
LD (PUT_B_1),HL ;банку.
LD HL,#C000
PUT_B_3 LD (PUT_B_2),HL
POP HL
POP AF
RET
| 2. | MAKE_PCX запись изображения из
трёх банков памяти в |
| Вход: | имя и расширение файла указано в NAME_EXT, номера банков памяти в N_BANK. |
Выход: | A=1 OK, A=0 записать файл не удалось (нет места на диске или в каталоге диска). |
;Структуры данных:
FILE_BUFER EQU #7000 ;Буфер для записи.
CAT_BUFER EQU #7100 ;Каталог диска.
;Пошла сама процедура:
ORG #6000
MAKE_PCX CALL INIT_GET
;Сначала преобразуем "вхолостую", чтобы
;узнать размер получаемого файла. В это
;время на бордюр выводятся цветные
;полосы - чтобы показать, что компьютер
;не завис.
LD D,0 ;DHL - длина.
LD HL,#381
LD BC,1
MAKE_PCX_1 CALL GET_BYTE
JR C,MAKE_PCX_2
AND 7 ;Изменяем
OUT (254),A ;BORDER.
ADD HL,BC
LD A,D
ADC A,0
LD D,A
JR MAKE_PCX_1
MAKE_PCX_2 LD (LEN_FILE),HL
LD A,D
LD (LEN_FILE+2),A
;Длина в байтах определена, теперь
;получаем длину в секторах:
LD BC,255
ADD HL,BC
LD A,D
ADC A,0
LD L,H
LD H,A ;HL - длина.
PUSH HL ;Запомнили её...
;Читаем каталог:
LD HL,CAT_BUFER
LD DE,0
LD B,9
LD C,5
CALL #3D13
;Проверка свободного места в области
;файлов:
LD HL,(CAT_BUFER+#8E5)
POP DE ;Длина файла.
XOR A ;A:=0, флаг C сброшен.
SBC HL,DE
RET C ;Нет места на диске!
;Коррекция свободного места:
LD (CAT_BUFER+#8E5),HL
;Теперь определяем, сколько будет
;файлов: один или два?
LD A,1 ;Кол-во файлов.
EX DE,HL
LD DE,255
SBC HL,DE ;Флаг C сброшен!
JR C,MAKE_PCX_7 ;1 файл.
INC A ;2 файла.
MAKE_PCX_7 LD (FILES),A
;Проверка свободного места в области
;каталога:
LD HL,CAT_BUFER+#8E4
LD B,(HL)
ADD A,B
LD (HL),A ;Коррекция.
CP 128+1
LD A,0
RET NC ;Нет места!
;Определяем номер первого сектора файла:
LD HL,(CAT_BUFER+#8E1)
LD (DISK_ADR),HL
;Помещаем в каталог информацию о файле
;(или о двух файлах, если длина больше
;#FF00):
LD H,0
LD L,B
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL ;*16
LD DE,CAT_BUFER
ADD HL,DE
EX DE,HL
LD HL,NAME_EXT ;Заголовок.
LD BC,11
LDIR
LD A,(FILES)
CP 2
JR NZ,MAKE_PCX_A
;Записывается два файла.
;Первый файл:
EX DE,HL
LD (HL),0 ;Длина:
INC HL
LD (HL),#FF ;#FF00 байтов,
INC HL
LD (HL),#FF ;#FF секторов.
INC HL
LD A,#FF ;Адрес на
CALL NEW_TS ;диске.
;Второй файл:
EX DE,HL
LD HL,NAME_EXT ;Заголовок.
LD BC,8
LDIR
LD A,"0" ;Первый символ
LD (DE),A ;расширения - "0".
INC DE
INC HL
LDI
LDI
EX DE,HL ;Длина:
LD A,(LEN_FILE) ;младший
LD (HL),A ;байт...
INC HL
PUSH HL
LD HL,(LEN_FILE+1)
DEC H
INC HL ;-#FF00
LD A,L ;и старший
POP HL ;байт.
LD (HL),A
PUSH HL
DEC HL
LD L,(HL)
LD H,A
INC H
DEC HL
LD A,H ;Длина в секторах.
POP HL
INC HL
LD (HL),A
INC HL
CALL NEW_TS
JR MAKE_PCX_9
;Записывается один файл:
MAKE_PCX_A EX DE,HL
LD DE,(LEN_FILE)
LD (HL),E ;Длина
INC HL ;в байтах.
LD (HL),D
INC HL
INC D ;Длина
DEC DE ;в секторах.
LD (HL),D
INC HL
LD A,D
CALL NEW_TS
;Записываем каталог:
MAKE_PCX_9 LD HL,CAT_BUFER
LD DE,0
LD B,9
LD C,6
CALL #3D13
;Записываем содержимое файла:
CALL OPEN_FILE
;Заголовок (128 байтов):
LD HL,HEADER
LD B,128
MAKE_PCX_6 LD A,(HL)
CALL PUT_BYTE
INC HL
DJNZ MAKE_PCX_6
;Данные о пикселах:
CALL INIT_GET
MAKE_PCX_3 CALL GET_BYTE
JR C,MAKE_PCX_4
CALL PUT_BYTE
JR MAKE_PCX_3
;Тип палитры:
MAKE_PCX_4 LD A,#0C
CALL PUT_BYTE
;Палитра (#300 байтов):
XOR A
MAKE_PCX_5 CALL PUT_BYTE
CALL PUT_BYTE
CALL PUT_BYTE
INC A
JR NZ,MAKE_PCX_5
;Закрываем файл:
CALL CLOSE_FILE
LD A,1
RET
NAME_EXT DB "picture pcx" ;Имя.
LEN_FILE DS 3 ;Длина pcx-файла.
FILES DS 1 ;Сколько будет файлов.
;---------------------------------------
;Процедура NEW_TS помещает по указанному
;в HL адресу сведения о первом
;свободном треке/секторе и обновляет
;эти сведения в системном секторе.
;
;Вход: A - длина файла в секторах.
;Выход: HL:=HL+2.
NEW_TS LD DE,(CAT_BUFER+#8E1)
LD (HL),E
INC HL ;Адрес на
LD (HL),D ;диске.
INC HL
;Увеличиваем номера первых незанятых
;трека/сектора:
LD B,A ;Длина в секторах
AND 15
ADD A,E
BIT 4,A
RES 4,A
LD E,A
JR Z,NEW_TS_1
INC D
NEW_TS_1 LD A,B
RRA
RRA
RRA
RRA
AND 15
ADD A,D
LD D,A
LD (CAT_BUFER+#8E1),DE
RET
;---------------------------------------
;Процедура GET_BYTE возвращает в
;аккумуляторе очередной байт упакованных
;данных о пикселах. Если флаг C
;установлен - значит, данные кончились.
;
;BC,DE,HL не изменяются.
STATUS DS 1 ;N состояния проц.
BYTE_B DS 1 ;Запомненный байт.
;Инициализация:
INIT_GET LD A,1
LD (STATUS),A
CALL INIT_PIX
RET
;Пошла сама процедура:
GET_BYTE PUSH BC
PUSH DE
PUSH HL
LD A,(STATUS)
CP 2
JR Z,GET_BYTE_2
;1-е состояние:
LD C,1 ;Счётчик одинаковых.
CALL GET_PIX
JR C,GET_EXIT
LD (BYTE_B),A
GET_B_3 LD A,C ;Уже есть 63
CP 63 ;одинаковых байта?
JR Z,GET_B_1
CALL GET_PIX ;Берём ещё байт.
JR C,GET_B_4
LD HL,BYTE_B ;Сравниваем...
CP (HL)
JR NZ,GET_B_4
INC C
JR GET_B_3
GET_B_4 CALL PREV_PIX ;Сдвиг назад.
GET_B_2 LD A,(BYTE_B);Байт выглядит
AND %11000000 ;как
CP %11000000 ;байт-счётчик?
JR Z,GET_B_1
LD A,C ;Одно
DEC A ;повторение?
JR NZ,GET_B_1
LD A,(BYTE_B)
AND A ;Сбрас. флаг C
JR GET_EXIT
GET_B_1 LD A,2
LD (STATUS),A
LD A,C
OR %11000000 ;Сбрас. флаг C
JR GET_EXIT
;2-е состояние:
GET_BYTE_2 LD A,1
LD (STATUS),A
LD A,(BYTE_B)
AND A ;Сбрас. флаг C
GET_EXIT POP HL
POP DE
POP BC
RET
;---------------------------------------
;Процедура GET_PIX последовательно
;возвращает данные о пикселах. Если
;флаг C установлен - значит, данные
;кончились.
;
;BC,DE,HL не изменяются.
GET_ADR DS 2 ;Адрес в банке памяти.
GET_BANK DS 1 ;Номер банка в таблице.
;Инициализация:
INIT_PIX LD HL,#C000-1
LD (GET_ADR),HL
XOR A
LD (GET_BANK),A
RET
;Пошла сама процедура:
GET_PIX PUSH HL
LD HL,(GET_ADR)
INC HL
LD (GET_ADR),HL
LD A,H
OR L
JR NZ,GET_PIX_1
LD HL,#C000
LD (GET_ADR),HL
LD A,(GET_BANK)
INC A
LD (GET_BANK),A
CP 3
JR NZ,GET_PIX_1
POP HL
SCF
RET
GET_PIX_1 PUSH BC
PUSH DE
LD BC,#7FFD
LD HL,N_BANK
LD A,(GET_BANK)
LD D,0
LD E,A
ADD HL,DE
LD A,(HL)
OUT (C),A
LD HL,(GET_ADR)
LD A,(HL)
LD D,#10
OUT (C),D
POP DE
POP BC
POP HL
AND A ;Сбрас. флаг C.
RET
;Сдвиг на пиксел назад:
PREV_PIX PUSH HL
LD HL,(GET_ADR)
DEC HL
LD A,H
CP #BF
JR NZ,PREV_PIX_1
LD A,L
CP #FF
JR NZ,PREV_PIX_1
LD HL,#FFFF
LD A,(GET_BANK)
DEC A
LD (GET_BANK),A
PREV_PIX_1 LD (GET_ADR),HL
POP HL
RET
;Банки данных с информацией о пикселах:
N_BANK DB #10,#11,#13
;---------------------------------------
;Процедуры для побайтной записи
;содержимого файла с буферизацией.
IN_BUF DS 1 ;Кол-во байтов в
;буфере.
DISK_ADR DS 2 ;Адрес сектора.
;OPEN_FILE - открыть файл.
OPEN_FILE XOR A
LD (IN_BUF),A
RET
;PUT_BYTE - записать байт в файл.
;Вход: A - записываемое значение.
;Выход: регистры не изменены.
PUT_BYTE PUSH AF
PUSH BC
PUSH DE
PUSH HL
LD B,A
LD A,(IN_BUF)
LD HL,FILE_BUFER
LD D,0
LD E,A
ADD HL,DE
LD (HL),B
INC A
LD (IN_BUF),A
;Если буфер заполнился - записываем его:
CALL Z,CLOSE_FILE
POP HL
POP DE
POP BC
POP AF
RET
;CLOSE_FILE - закрыть файл.
;Содержимое буфера записывается на диск.
CLOSE_FILE LD DE,(DISK_ADR)
PUSH DE
LD B,1
LD C,6
LD HL,FILE_BUFER
CALL #3D13
POP DE
INC E
LD A,E
AND 15
LD E,A
JR NZ,CLOSE_EXIT
INC D
CLOSE_EXIT LD (DISK_ADR),DE
RET
;---------------------------------------
;128-байтный заголовок:
HEADER
db #0A,#05,#01,#08,#00,#00,#00,#00
db #FF,#00,#BF,#00,#00,#01,#C0,#00
db #60,#61,#62,#63,#64,#65,#66,#67
db #68,#69,#6A,#6B,#6C,#6D,#6E,#6F
db #70,#71,#72,#73,#74,#75,#76,#77
db #78,#79,#7A,#7B,#3F,#00,#00,#00
db #50,#D6,#B0,#01,#14,#01,#00,#00
db #C5,#B9,#F7,#BF,#C4,#30,#92,#81
db #01,#01,#00,#01,#01,#00,#00,#00
db #00,#00,#00,#00,#00,#00,#00,#00
db #00,#00,#00,#00,#00,#00,#00,#00
db #00,#00,#00,#00,#00,#00,#00,#00
db #00,#00,#00,#00,#00,#00,#00,#00
db #00,#00,#00,#00,#00,#00,#00,#00
db #00,#00,#00,#00,#00,#00,#00,#00
db #00,#00,#00,#00,#00,#00,#00,#00
| 3. | SCR2BANK преобразование
изображения в спектрумовском формате в |
| Вход: | исходное изображение загружено с #4000, номера банков памяти в N_BANK, яркости градаций в BRIGHT_0 и BRIGHT_1. |
ORG #8000
SCR2BANK LD HL,N_BANK
LD (PUT_B_1),HL
LD HL,#C000
LD (PUT_B_2),HL
LD DE,0
MAIN CALL GET_PIX
LD B,A
AND 7 ;Индикация
OUT (254),A ;на бордюре.
LD A,B
CALL PUT_B
INC D
JR NZ,MAIN
INC E
LD A,E
CP 192
JR NZ,MAIN
RET
;Номера используемых банков памяти:
N_BANK DB #10,#11,#13
;---------------------------------------
;Процедура GET_PIX возвращает яркость
;указанного пиксела изображения.
;
;Вход: DE - координаты пиксела.
;Выход: A - яркость (0..255).
GET_PIX PUSH DE
;Определяем INK, PAPER, BRIGHT:
LD H,0
LD A,E
AND %11111000
LD L,A
ADD HL,HL
ADD HL,HL
LD A,D
RRA
RRA
RRA
AND %00011111
LD E,A
LD D,#58
ADD HL,DE
LD A,(HL)
RRA
RRA
AND %00010000
LD (BRIGHT),A
LD A,(HL)
AND 7
LD (INK),A
LD A,(HL)
RRA
RRA
RRA
AND 7
LD (PAPER),A
POP DE
PUSH DE
CALL BYTE
AND (HL)
LD A,0
PAPER EQU $-1
JR Z,GET_PIX_1
LD A,0
INK EQU $-1
GET_PIX_1 ADD A,A
ADD A,0
BRIGHT EQU $-1
LD E,A
LD D,0
LD HL,BRIGHT_0
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
LD HL,#80
ADD HL,DE
LD A,H
POP DE
RET
BYTE LD A,E
AND A
RRA
SCF
RRA
AND A
RRA
XOR E
AND #F8
XOR E
LD H,A
LD A,D
RLCA
RLCA
RLCA
XOR E
AND #C7
XOR E
RLCA
RLCA
LD L,A
LD A,D
AND 7
LD B,A
INC B
LD A,1
LOOP RRCA
DJNZ LOOP
RET
;---------------------------------------
;Яркости градаций в формате 8.8:
BRIGHT_0 DW 0,1112,2139,4412,6062
DW 14555,26811,46556
BRIGHT_1 DW 0,1369,3129,6062,8995
DW 21704,38045,65280
;---------------------------------------
;Процедура PUT_B - запись в память
;информации об очередном пикселе.
;
;Вход: A - значение пиксела.
PUT_B PUSH AF ;Устанавливаем
LD A,(0) ;нужный
PUT_B_1 EQU $-2 ;банк
LD BC,#7FFD ;памяти.
OUT (C),A
POP AF
LD HL,0 ;Записываем.
PUT_B_2 EQU $-2
LD (HL),A
INC HL ;Увеличиваем
LD A,H ;адрес.
OR L
JR NZ,PUT_B_3
LD HL,(PUT_B_1) ;Переход к
INC HL ;следующему
LD (PUT_B_1),HL ;банку.
LD HL,#C000
PUT_B_3 LD (PUT_B_2),HL
RET