Login

Subversion Repositories NedoOS

Rev

Rev 344 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

LINEPNG=0x8008
LINEPNGTEMP=0x9000 ;для конвертации 16bit->8bit (TODO в конце LINEPNGPRIOR)
LINEPNGPRIOR=0xa008

        align 256
PNGPAL
        ds 768 ;TODO убрать в страничку

readpng
        ld b,7
        call read_b_bytes ;TODO test header

readpng_chunk
        call RDWORDHSBLSBtohl
        ex de,hl
        call RDWORDHSBLSBtohl ;dehl=chunk size
        exx
        call GETDWORD_slow ;e,d,l,h

        ld a,e
        cp 'I'
        jr z,readpng_chunk_IHDR_IDAT
        cp 'P'
        jr z,readpng_chunk_PLTE
        jr readpng_skiprestofchunk
       
readpng_chunk_IHDR_IDAT
        ld a,d
        cp 'D'
        jp z,readpng_chunk_IDAT
        cp 'E'
        ret z ;IEND
readpng_chunk_IHDR
        call RDWORDHSBLSBtohl
        call RDWORDHSBLSBtohl ;hl=width
        call setpicwid
        call RDWORDHSBLSBtohl
        call RDWORDHSBLSBtohl ;hl=hgt
        call setpichgt
        call RDBYTE ;bit depth (глубина цвета 1, 2, 4, 8, 16)
         ld (readpng_bitdepth),a
        add a,7 ;8,9,11,15,23
        rra
        rra
        rra
        and 3 ;1,1,1,1,2
        ld e,a
        call RDBYTE ;color type (тип цвета: 1 (индексированный цвет - с палитрой) + 2 (цветное изображение, т.е. не Grayscale) + 4 (используется альфа-канал))
         ld (readpng_palflag_bit0),a
         rra
         ld d,1
         jr c,readpng_countbppok
         rra
         jr nc,$+4
         ld d,3
         rra
         jr nc,$+3
         inc d
readpng_countbppok
         ld a,d
         dec e
         jr z,$+3
         add a,a
        ld (png_bytesperpix),a

        call RDBYTE ;compression method (0 = deflate)
        call RDBYTE ;filter method (=0)
        call RDBYTE ;interlace method (0 (нет чередования) / 1 (Adam7 interlace)) ;TODO

        call initframe ;один раз на кадр после setpicwid, setpichgt и после установки gifframetime ;заказывает память под конверченный кадр

        call GETDWORD_slow ;e,d,l,h
        jr readpng_chunk

readpng_chunk_PLTE
        exx
        ;hl=chunk size
        dec hl
        ld e,0
readpng_chunk_PLTE0
        ld d,PNGPAL/256
        call RDBYTE
        ld (de),a
        inc d
        call RDBYTE
        ld (de),a
        inc d
        call RDBYTE
        ld (de),a
        inc e
        ld bc,3
        or a
        sbc hl,bc
        jp p,readpng_chunk_PLTE0

        call GETDWORD_slow ;e,d,l,h
        jp readpng_chunk

readpng_skiprestofchunk
;after chunk name: skip chunk size + 4 bytes (CRC)
        exx
;dehl=chunk size
readpng_skiprestofchunk0
        ld c,l ;1..0
        xor a
        ld b,a;0
        dec c ;0..255
        inc bc ;1..256
        ;or a
        sbc hl,bc
        jr nc,$+3
         dec de
        ld b,c
        call read_b_bytes
        ld a,d
        or e
        or h
        or l
        jr nz,readpng_skiprestofchunk0
        call GETDWORD_slow ;e,d,l,h
        jp readpng_chunk

readpng_chunk_IDAT
;заказать память под блок данных hgt*(wid*bytesperpix+1):
; if bpp=1
; then RawLen:=IHDRData.Width div bp+1 {bp:=8 div BitDepth} {реально надо округление вверх??? TODO проверить - сделал вверх}
; else RawLen:=IHDRData.Width*bpp+1;
;теоретически сейчас в DISKBUF может быть больше, чем размер текущего IDAT (хотя реально разрезают IDAT по 8K)        
;TODO переставить указатель файла на текущий байт и прочитать на размер текущего IDAT (если это меньше DUSKBUFsz)
;а пока без перестановки указателя - узнаем, какую часть IDAT мы уже прочитали, и вычитаем её из chunk size
;chunksize -= DISKBUF+DISKBUFsz-(iy+1) ;может быть 0
;[chunksize += iy + (1 - (DISKBUF+DISKBUFsz)) ;может быть 0]
        exx
;dehl=chunk size
        push iy
        pop bc
        push hl
        ld hl,DISKBUF+DISKBUFsz-1
        or a
        sbc hl,bc
        ld b,h
        ld c,l ;iy + (1 - (DISKBUF+DISKBUFsz))
        pop hl
        or a
        sbc hl,bc
        jr nc,$+3
         dec de
        ld (pngIDATremained),hl
        ld (pngIDATremainedHSW),de

        ld hl,(freemem_hl)
        ld a,(freemem_a)
        ld (pngdepktoaddr),hl
        ld (pngdepktoaddrHSB),a
        ld (pngdecodefromaddr),hl
        ld (pngdecodefromaddrHSB),a

        ld de,(curpicwid)
png_bytesperpix=$+1
        ld bc,0
        call MULWORD ;hlbc=de*bc

        ld a,(readpng_bitdepth)
        cp 8
        jr nc,readpng_chunk_IDATlinesizeok ;нельзя генерить палитру, т.к. бывает YA?
        cp 4
         ld e,17
        jr z,readpng_chunk_IDATlinesizediv2
        cp 2
         ld e,85
        jr z,readpng_chunk_IDATlinesizediv4
         ld e,255
        inc bc
        srl b
        rr c
readpng_chunk_IDATlinesizediv4
        inc bc
        srl b
        rr c
readpng_chunk_IDATlinesizediv2
        inc bc
        srl b
        rr c
;сгенерировать нужную серую палитру:
         ld a,(readpng_palflag_bit0)
         rra
         jr c,readpng_chunk_IDATlinesizeok ;настоящую палитру уже прочитали

        push hl
        xor a
        ld l,a
;4bits: step=17
;2bits: step=85
;1bit: step=255
readpng_getgreypal0
        ld h,PNGPAL/256
        ld (hl),a
        inc h
        ld (hl),a
        inc h
        ld (hl),a
        add a,e;step
        inc l
        jr nz,readpng_getgreypal0
        pop hl

         ld a,1
         ld (readpng_palflag_bit0),a
readpng_chunk_IDATlinesizeok
         ld (png_bytesperline),bc
        inc bc ;every line starts with subfilter byte
         ;bc=physical line data size
        ld de,(curpichgt)
        call MULWORD ;hlbc=de*bc = размер блока данных
        ld d,b
        ld e,c
;hlde=size
        call reserve_mem ;портит номер банка в 0xc000
         call gifsetpgLZW

;zlib/gzip header:
        call RDBYTE ;0xW8, W=max window
        call RDBYTE ;7..6=compression level, 5=DICT (TODO read 4 bytes - и что с ними делать?), 4..0=for multiple of 31
;
       
        call INFLATING

;render:
        ld hl,LINEPNGPRIOR
        ld de,LINEPNGPRIOR+1
        ld bc,(png_bytesperline)
        dec bc
        ld (hl),BACKGROUNDCOLORLEVEL
        ldir
        ld hl,0
        ld (LINEPNG-2),hl
        ld (LINEPNG-4),hl ;чтобы не проверять k>=bpp
        ld (LINEPNG-6),hl
        ld (LINEPNG-8),hl ;чтобы не проверять k>=bpp
        ld (LINEPNGPRIOR-2),hl
        ld (LINEPNGPRIOR-4),hl ;чтобы не проверять k>=bpp
        ld (LINEPNGPRIOR-6),hl
        ld (LINEPNGPRIOR-8),hl ;чтобы не проверять k>=bpp

pngdecodefromaddr=$+1
        ld hl,0
pngdecodefromaddrHSB=$+1
        ld a,0

        ld bc,(curpichgt)
renderpng_lines0
        push bc
        call readbyte ;subfilter byte
         ld lx,c

        ld de,LINEPNG
png_bytesperline=$+1
        ld bc,0
        push bc
        push af
        push hl
        call getfrommem
        pop hl
        pop af
        pop bc
        add hl,bc
        adc a,0
        push af
        push hl
       
        ld bc,(png_bytesperpix)
        ld de,LINEPNG
        ld hl,LINEPNGPRIOR
        push hl
        push de
        ;or a
        sbc hl,bc
        ex de,hl
        ;or a
        sbc hl,bc
        exx
        pop hl ;LINEPNG
        pop de ;LINEPNGPRIOR
        ld bc,(png_bytesperline)
        ld a,lx
        or a
        jr z,pngfilterq
        dec a
        jr z,png_sub
        dec a
        jr z,png_up
        dec a
        jr z,png_average
         ;dec a
         ;jr nz,$
png_paeth
;      if k>=bpp
;      then inc(ImageData[i],PaethPredictor(Raw[k-bpp],Prior[k],Prior[k-bpp]))
;      else inc(ImageData[i],PaethPredictor(0,Prior[k],0));
        exx
        ex de,hl
        exx
renderpng_paeth0
        ld a,(de)
        exx
        call paethpredictor ;(de),a,(hl)
        inc hl
        inc de
        exx
        add a,(hl)
        ld (hl),a
        inc de
        cpi
        jp pe,renderpng_paeth0
        jr pngfilterq
png_sub
;      if k>=bpp
;      then inc(ImageData[i],Raw[k-Bpp]);
        exx
        push hl ;raw-
        exx
        pop de
png_up
;      inc(ImageData[i],Prior[k]);
renderpng_up0
        ld a,(de) ;prior
        add a,(hl)
        ld (hl),a
        inc de
        cpi
        jp pe,renderpng_up0
        jr pngfilterq
png_average
;      if k>=bpp
;      then inc(ImageData[i],(Raw[k-bpp]+Prior[k])div 2)
;      else inc(ImageData[i],Prior[k]div 2);
renderpng_average0
        ld a,(de)
        exx
        add a,(hl)
        inc hl
        exx
        rra
        add a,(hl)
        ld (hl),a
        inc de
        cpi
        jp pe,renderpng_average0
       
pngfilterq
        call islinevisible
        jp nz,renderpng_lineinvisible

;конвертировать составляющие из 16bit в 8bit:
        ld hl,LINEPNG
        ld de,LINEPNGPRIOR ;result of recolor
        ld a,(readpng_bitdepth)
        cp 16
        ld a,(png_bytesperpix)
        jr nz,pngrecolor16q
        rra
        push de
        ld de,LINEPNGTEMP ;TODO в конце PRIOR
        push de
        ld bc,(png_bytesperline)
        srl b
        rr c
pngrecolor160
        inc hl
        ldi
        jp pe,pngrecolor160
        pop hl
        pop de ;будем перекодировать TEMP->PRIOR
pngrecolor16q
;конвертировать из bpp в 24bit:
;hl=from
;de=to
;a=число цветовых составляющих(1..4)
        ld bc,(curpicwid)
        dec a
        jr z,pngrecolor1
        dec a
        jp z,pngrecolor2
        dec a
        jp z,pngrecolor3
;32bpp: RGBA -> BGR
pngrecolorRGBA0
        ld a,(hl)
        inc hl
        ex af,af' ;R
        ld a,(hl) ;G
        inc hl
        ldi ;B
        ld (de),a ;G
        inc de
        ex af,af'

        ld (de),a ;R
        inc de
        ex af,af'
        inc hl ;skip A
        jp pe,pngrecolorRGBA0
        jp pngrecolorq
pngrecolor1
;8bpp: Y -> BGR
readpng_palflag_bit0=$+1
        ld a,0
        rra
        jp nc,pngrecolorY0
readpng_bitdepth=$+1
        ld a,0
        cp 8
        jr z,pngrecolorPAL80
        cp 4
        jr z,pngrecolorPAL4
        cp 2
        jr z,pngrecolorPAL2
pngrecolorPAL1
;bc = (bc+7)/8 = (bc-1)/8 + 1
        dec bc
        ld a,c
        srl b
        rra
        srl b
        rra
        srl b
        rra
        ld c,a
        inc bc
pngrecolorPAL10
        push hl
        ld a,(hl)
        scf
        rla
pngrecolorPAL100
        ld l,0
        rl l
        call pngrepal
        inc bc ;ldi compensation
        add a,a
        jr nz,pngrecolorPAL100
        pop hl
        cpi
        jp pe,pngrecolorPAL10
        jp pngrecolorq
pngrecolorPAL4
;round least bit up
        inc bc
        res 0,c
pngrecolorPAL40
        push hl
        ld a,(hl)
        push af
        rra
        rra
        rra
        rra
        and 0x0f
        ld l,a
        call pngrepal
        pop af
        and 0x0f
        ld l,a
        call pngrepal
        pop hl
        inc hl
        jp pe,pngrecolorPAL40
        jr pngrecolorq      
pngrecolorPAL2        
;round 2 least bits up
        inc bc
        inc bc
        inc bc
        res 1,c
        res 0,c
pngrecolorPAL20
        push hl
        ld a,(hl)
        call pngrepal2bits
        call pngrepal2bits
        call pngrepal2bits
        call pngrepal2bits
        pop hl
        inc hl
        jp pe,pngrecolorPAL20
        jr pngrecolorq
pngrecolorPAL80
        push hl
        ld l,(hl)
        call pngrepal
        pop hl
        inc hl
        jp pe,pngrecolorPAL80
        jr pngrecolorq
pngrecolorY0
        ld a,(hl)
        ldi ;B
        ld (de),a ;G
        inc de
        ld (de),a ;R
        inc de
        jp pe,pngrecolorY0
        jr pngrecolorq
pngrecolor2
;16bpp: YA -> BGR
pngrecolorYA0
        ld a,(hl)
        ldi ;B
        ld (de),a ;G
        inc de
        ld (de),a ;R
        inc de
        inc hl ;skip A
        jp pe,pngrecolorYA0
        jr pngrecolorq
pngrecolor3
;24bpp: RGB -> BGR
pngrecolorRGB0
        ld a,(hl)
        inc hl
        ex af,af'
;R
        ld a,(hl) ;G
        inc hl
        ldi ;B
        ld (de),a ;G
        inc de
        ex af,af'
        ld (de),a ;R
        inc de
        ex af,af'
       
        jp pe,pngrecolorRGB0
        jr pngrecolorq
pngrecolorq
        ld h,d
        ld l,e
        ld (hl),b;0
        inc de
        ld bc,7*3-1
        ldir ;чтобы справа в остатке знакоместа была чернота (потом можно убрать, когда readchr будет это делать)

        ld hl,LINEPNGPRIOR ;recolored line
        call drawscreenline_frombuf ;конвертируем LINEGIF в LINEPIXELS и выводим её на экран
        call keepconvertedline ;запоминаем сконверченную строку из LINEPIXELS
        call nextoldconvertedframeaddr ;смещаем адрес, откуда брать сконверченную строку из предыдущего кадра (gifoldconvertedframeaddr)
renderpng_lineinvisible
        call inccury

        ld hl,LINEPNG
        ld de,LINEPNGPRIOR
        ld bc,(png_bytesperline)
        ldir ;TODO менять местами указатели
       
        pop hl
        pop af
       
        pop bc
        dec hl
        cpi
        jp pe,renderpng_lines0

        ret ;остальное нас не интересует (курсор файла после unzip в случайном положении?)

;function TPNG.PaethPredictor(a,b,c:BYTE):byte;
; var
;   pa,pb,pc:integer;
; begin {PaethPredictor}
;   pc:=a+b-c;
;   pa:=abs(pc-a); pb:=abs(pc-b); pc:=abs(pc-c);
;   if(pa<=pb)and(pa<=pc)
;   then Result:=a
;   else
;    if pb>pc
;    then Result:=c
;    else Result:=b;
; end; {PaethPredictor}
paethpredictor
;?a=(de),?b=a,?c=(hl)
;out: a
        ld hx,a;?b
        sub (hl);?c
        jr nc,$+4
          neg
         ld ly,a;?pa,a ;pa=abs(b-c)
         
        ld a,(de);?a
        sub (hl);?c
        jr nc,$+4
          neg
         ld hy,a;?pb,a ;pb=abs(a-c)
         
        ld a,(de);?a
        add a,hx;?b
        rra
        jr c,paeth1
        sub (hl);?c ;a=(a+b-2c)/2
        jr nc,$+4
          neg
        add a,a
        jp paethpredok
paeth1
        sub (hl);?c ;a=(a+b-2c)/2 - 1/2 ;1 вместо 1.5, -1 вместо -0.5
        jr nc,$+3
          cpl ;-1 (означает -0.5) => 0 (означает 0.5)
        scf
        rla
paethpredok
        jr nc,$+3
          sbc a,a
         ld lx,a;?pc,a ;pc=abs(a+b-2c) ;если >255, то 255
         
        ld a,hy;?pb
        cp ly;?pa
        jr c,paethpredictor_resultnoa ;pa>pb
        ld a,lx;?pc
        cp ly;?pa
        jr nc,paethpredictor_resulta ;(pa<=pb)and(pa<=pc)
paethpredictor_resultnoa
        ld a,lx;?pc
        cp hy;?pb
        jr c,paethpredictor_resultc ;pb>pc
        ld a,hx;?b
        ret
paethpredictor_resultc
        ld a,(hl);?c
        ret
paethpredictor_resulta
        ld a,(de);?a
        ret

pngrepal2bits
        ld l,0
        rla
        rl l
        rla
        rl l
pngrepal
;l=color index
;write 3 bytes from pal to (de)
;keeps a
;decrements bc with P/V flag
        ld h,PNGPAL/256+2
        ex af,af'
        ld a,(hl) ;B
        ld (de),a
        inc de
        dec h
        ld a,(hl) ;G
        ld (de),a
        ex af,af'

        inc de
        dec h
        ldi ;R
        ret