kolibrios/programs/develop/libraries/libs-dev/libimg/png/png.asm
Ivan Baravy 459cb3ec5b libimg: Improve support of transparent PNG images.
* Support grayscale images with alpha channel.
* Support rgb images with transparent color.
* Process 'tRNS' chunk (simple transparency).

Transparent png images were already supported for color type 6, which
is RGBA. Now indexed images (color type 3) can also have transparency
via 'tRNS' chunk data.

git-svn-id: svn://kolibrios.org@8449 a494cfbc-eb01-0410-851d-a64ba20cac60
2020-12-18 22:08:51 +00:00

1222 lines
25 KiB
NASM

;;================================================================================================;;
;;//// png.asm //// (c) diamond, 2009 ////////////////////////////////////////////////////////////;;
;;================================================================================================;;
;; ;;
;; This file is part of Common development libraries (Libs-Dev). ;;
;; ;;
;; Libs-Dev is free software: you can redistribute it and/or modify it under the terms of the GNU ;;
;; Lesser General Public License as published by the Free Software Foundation, either version 2.1 ;;
;; of the License, or (at your option) any later version. ;;
;; ;;
;; Libs-Dev is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without ;;
;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;
;; Lesser General Public License for more details. ;;
;; ;;
;; You should have received a copy of the GNU Lesser General Public License along with Libs-Dev. ;;
;; If not, see <http://www.gnu.org/licenses/>. ;;
;; ;;
;;================================================================================================;;
include 'libpng/png.asm'
;;================================================================================================;;
;;proc img.is.png _data, _length ;////////////////////////////////////////////////////////////////;;
img.is.png:
;;------------------------------------------------------------------------------------------------;;
;? Determine if raw data could be decoded (is in PNG format) ;;
;;------------------------------------------------------------------------------------------------;;
;> _data = raw data as read from file/stream ;;
;> _length = data length ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = false / true ;;
;;================================================================================================;;
; test 1 (length of data)
cmp dword [esp+8], 8
jb .nope
; test 2: signature
mov eax, [esp+4]
cmp dword [eax], 0x474E5089
jne .nope
cmp dword [eax+4], 0x0A1A0A0D
je .yep
.nope:
xor eax, eax
ret 8
.yep:
xor eax, eax
inc eax
ret 8
;endp
;;================================================================================================;;
;;proc img.decode.png _data, _length, _options ;//////////////////////////////////////////////////;;
img.decode.png:
xor eax, eax ; .image = 0
pushad
mov ebp, esp
.localsize = 30*4
virtual at ebp - .localsize
.width dd ?
.height dd ?
.bit_depth dd ?
.color_type dd ?
.transparent_color dd ?
.bytes_per_pixel dd ?
.scanline_len dd ?
.bits_per_pixel dd ?
.size_rest dd ?
.cur_chunk_ptr dd ?
.cur_chunk_size dd ?
.allocated dd ?
.paeth_a dd ?
.paeth_b dd ?
.paeth_c dd ?
.paeth_pa dd ?
.paeth_pb dd ?
.paeth_pc dd ?
.i dd ?
.j dd ?
; variables to handle interlace
.row_distance dd ? ; diff between two consecutives rows in destination
.col_distance dd ? ; summand for moving to next row in source
.row_increment dd ?
.col_increment dd ?
.block_height dd ?
.block_width dd ?
.interlace db ? ; 0 if not interlaced, 1 if interlaced
.row_increment_shift db ?
.col_increment_shift db ?
.shift db ? ; shift for current src byte
.starting_row dd ?
.starting_col dd ?
.idat_read dd ?
rb 1Ch
.image dd ?
rd 1
.data dd ?
.length dd ?
.options dd ?
end virtual
push eax ; .idat_read = 0
push eax ; .starting_col = 0
push eax ; .starting_row = 0
push eax ; .col_increment_shift, .row_increment_shift
inc eax
push eax ; .block_width
push eax ; .block_height
push eax ; .col_increment
push eax ; .row_increment
sub esp, .localsize-32
; load deflate unpacker, if not yet
; acquire mutex
@@:
push 1
pop eax
xchg [deflate_loader_mutex], eax ; 'xchg' has an implicit 'lock' prefix
test eax, eax
jz @f
mcall 5, 1
jmp @b
@@:
cmp [deflate_unpack2], __deflate_unpack2_import_name__
jnz .deflate_loaded
; do loading
invoke dll.load, @IMPORT
test eax, eax
jz .deflate_loaded
add esp, .localsize
popad
mov [deflate_loader_mutex], eax
ret 12
.deflate_loaded:
; release mutex
mov [deflate_loader_mutex], 0
; ok, continue
mov esi, [.data] ; esi -> data
mov ecx, [.length] ; ecx = length
; the signature has been already checked in img.is.png
lodsd
lodsd
sub ecx, 8
xor ebx, ebx ; no image allocated
.chunks_loop:
sub ecx, 12
jc .eof
lodsd ; chunk length
bswap eax
sub ecx, eax
jc .eof
push ecx ; save length of data rest
xchg eax, ecx ; ecx = size of data in the chunk
lodsd ; chunk type
cmp eax, 'IHDR'
jz .ihdr
cmp eax, 'IDAT'
jz .idat
cmp eax, 'IEND'
jz .iend
cmp eax, 'PLTE'
jz .palette
cmp eax, 'tRNS'
jz .transparency
; unrecognized chunk, ignore
lea esi, [esi+ecx+4]
pop ecx
jmp .chunks_loop
; IHDR chunk
.ihdr:
cmp ecx, 13
jnz .invalid_chunk
cmp [.image], 0
jnz .invalid_chunk
; read image characteristics
lodsd
bswap eax
mov [.width], eax
lodsd
bswap eax
mov [.height], eax
xor eax, eax
lea ebx, [eax+1]
lodsb
cmp al, 16
ja .invalid_chunk
test al, al
jz .invalid_chunk
lea edx, [eax-1]
test al, dl
jnz .invalid_chunk
mov [.bit_depth], eax
lodsb
test al, not 7
jnz .invalid_chunk
mov [.color_type], eax
lodsb
test al, al
jnz .invalid_chunk ; only compression method 0 is defined
lodsb
test al, al
jnz .invalid_chunk ; only filtering method 0 is defined
lodsb
cmp al, 1
ja .invalid_chunk ; only interlacing methods 0 and 1 are defined
mov [.interlace], al
; check for correctness and calculate bytes_per_pixel and scanline_len
mov eax, [.bit_depth]
mov edx, [.color_type]
dec edx
js .grayscale1
dec edx
jz .rgb1
dec edx
jz .palette1
dec edx
jz .grayscale_alpha1
dec edx
dec edx
jnz .invalid_chunk
.rgb_alpha1:
inc ebx
.rgb1:
inc ebx
.grayscale_alpha1:
inc ebx
cmp al, 8
jb .invalid_chunk
jmp @f
.palette1:
cmp al, 8
ja .invalid_chunk
.grayscale1:
@@:
mul ebx
mov [.bits_per_pixel], eax
add eax, 7
shr eax, 3
mov [.bytes_per_pixel], eax
mov [.transparent_color], 0
; allocate image
movi eax, Image.bpp32
cmp [.color_type], 2
jz @f
mov al, Image.bpp32
cmp [.color_type], 6
jz @f
mov al, Image.bpp8a
cmp [.color_type], 4
jz @f
mov al, Image.bpp8i
@@:
stdcall img.create, [.width], [.height], eax
test eax, eax
jz .invalid_chunk
mov [.image], eax
jmp .next_chunk
.invalid_chunk:
.iend:
pop ecx
.eof:
add esp, .localsize
popad
ret 12
; PLTE chunk
.palette:
mov eax, [.image]
test eax, eax
jz .invalid_chunk
cmp [.color_type], 3
jz .copy_palette
.ignore_chunk:
add esi, ecx
.next_chunk:
lodsd
pop ecx
jmp .chunks_loop
.copy_palette:
mov edi, [eax + Image.Palette]
xor eax, eax
cmp ecx, 256*3
ja .next_chunk
@@:
sub ecx, 3
jz @f
js .invalid_chunk
lodsd
dec esi
bswap eax
mov al, 0xff
ror eax, 8
stosd
jmp @b
@@:
lodsd
dec esi
bswap eax
mov al, 0xff
ror eax, 8
stosd
jmp .next_chunk
; convert 16 bit sample to 8 bit sample
macro convert_16_to_8
{
local .l1,.l2
xor ah, 0x80
js .l1
cmp al, ah
adc al, 0
jmp .l2
.l1:
cmp ah, al
sbb al, 0
.l2:
}
; tRNS chunk
.transparency:
mov eax, [.image]
test eax, eax
jz .invalid_chunk
cmp [.color_type], 2 ; rgb
jz .transparency_rgb
cmp [.color_type], 3 ; indexed
jz .transparency_indexed
add esi, ecx
jmp .next_chunk
.transparency_rgb:
cmp [.bit_depth], 16
jz .transparency_rgb16
lodsw
shl eax, 8
lodsw
shl eax, 8
lodsw
mov al, 0xff
ror eax, 8
mov [.transparent_color], eax
jmp .next_chunk
.transparency_rgb16:
lodsw
convert_16_to_8
shl ax, 8
shl eax, 8
lodsw
convert_16_to_8
shl ax, 8
shl eax, 8
lodsw
convert_16_to_8
shl ax, 8
mov al, 0xff
ror eax, 8
mov [.transparent_color], eax
jmp .next_chunk
.transparency_indexed:
mov edi, [eax + Image.Palette]
@@:
add edi, 3
movsb
loop @b
jmp .next_chunk
.idat:
test ecx, ecx
jz .next_chunk
cmp [.idat_read], 0
jnz @f
lodsb
inc [.idat_read]
and al, 0xF
cmp al, 8
jnz .invalid_chunk
dec ecx
jz .next_chunk
@@:
cmp [.idat_read], 1
jnz @f
lodsb
inc [.idat_read]
test al, 20h
jnz .invalid_chunk
dec ecx
jz .next_chunk
@@:
mov [.cur_chunk_ptr], esi
mov [.cur_chunk_size], ecx
pop [.length]
push eax
push esp
push ebp
push .deflate_callback
call [deflate_unpack2]
pop ecx
test eax, eax
jz .invalid_chunk
; convert PNG unpacked data to RAW data
mov esi, eax
mov [.allocated], eax
mov [.size_rest], ecx
; unfilter and deinterlace
; .interlace_pass, .starting_row and .starting_col have been already set to 0
; .block_width, .block_height, .col_increment, .row_increment were set
; to values for non-interlaced images; correct if necessary
cmp [.interlace], 0
jz .deinterlace_loop
push 8
pop eax
mov [.row_increment], eax
mov [.col_increment], eax
mov [.block_height], eax
mov [.block_width], eax
mov [.row_increment_shift], 3
mov [.col_increment_shift], 3
.deinterlace_loop:
mov edx, [.height]
cmp edx, [.starting_row]
jbe .deinterlace_next
mov ebx, [.width]
sub ebx, [.starting_col]
jbe .deinterlace_next
mov cl, [.col_increment_shift]
add ebx, [.col_increment]
dec ebx
shr ebx, cl
mov eax, [.bits_per_pixel]
imul eax, ebx
add eax, 7
shr eax, 3
mov [.scanline_len], eax
shl ebx, cl
mov [.col_distance], ebx
; Unfilter
mov ecx, [.size_rest]
push esi
.unfilter_loop_e:
mov ebx, [.scanline_len]
sub ecx, 1
jc .unfilter_abort
sub ecx, ebx
jc .unfilter_abort
movzx eax, byte [esi]
add esi, 1
cmp eax, 4
ja .next_scanline
jmp dword [@f + eax*4]
align 4
@@:
dd .unfilter_none
dd .unfilter_sub
dd .unfilter_up
dd .unfilter_average
dd .unfilter_paeth
.unfilter_sub:
mov edi, [.bytes_per_pixel]
add esi, edi
sub ebx, edi
jbe .next_scanline
neg edi
@@:
mov al, [esi+edi]
add [esi], al
add esi, 1
sub ebx, 1
jnz @b
jmp .next_scanline
.unfilter_up:
cmp edx, [.height]
jz .unfilter_none
lea edi, [ebx+1]
neg edi
@@:
mov al, [esi+edi]
add [esi], al
add esi, 1
sub ebx, 1
jnz @b
jmp .next_scanline
.unfilter_average:
mov edi, [.bytes_per_pixel]
cmp edx, [.height]
jz .unfilter_average_firstline
push edx
lea edx, [ebx+1]
neg edx
sub ebx, edi
@@:
mov al, [esi+edx]
shr al, 1
add [esi], al
add esi, 1
sub edi, 1
jnz @b
mov edi, [.bytes_per_pixel]
neg edi
test ebx, ebx
jz .unfilter_average_done
@@:
mov al, [esi+edx]
add al, [esi+edi]
rcr al, 1
add [esi], al
add esi, 1
sub ebx, 1
jnz @b
.unfilter_average_done:
pop edx
jmp .next_scanline
.unfilter_average_firstline:
mov edi, [.bytes_per_pixel]
add esi, edi
sub ebx, edi
jbe .next_scanline
neg edi
@@:
mov al, [esi+edi]
shr al, 1
add [esi], al
add esi, 1
sub ebx, 1
jnz @b
jmp .unfilter_none
.unfilter_paeth:
cmp edx, [.height]
jz .unfilter_sub
push edx
lea edx, [ebx+1]
mov edi, [.bytes_per_pixel]
neg edx
sub ebx, edi
@@:
mov al, [esi+edx]
add [esi], al
add esi, 1
sub edi, 1
jnz @b
mov edi, [.bytes_per_pixel]
neg edi
test ebx, ebx
jz .unfilter_paeth_done
push ecx
@@:
push ebx
; PaethPredictor(Raw(x-bpp) = a, Prior(x) = b, Prior(x-bpp) = c)
movzx eax, byte [esi+edi]
mov [.paeth_a], eax
movzx ecx, byte [esi+edx]
add edi, edx
mov [.paeth_b], ecx
add ecx, eax
movzx eax, byte [esi+edi]
mov [.paeth_c], eax
sub ecx, eax ; ecx = a + b - c = p
; calculate pa = abs(p-a), pb = abs(p-b), pc = abs(p-c)
mov ebx, ecx
sub ebx, eax ; ebx = p - c
cmp ebx, 80000000h
sbb eax, eax ; eax = (p < c) ? 0 : 0xFFFFFFF
not eax ; eax = (p < c) ? 0xFFFFFFFF : 0
and eax, ebx ; eax = (p < c) ? p - c : 0
sub ebx, eax
sub ebx, eax ; ebx = abs(p-c)
mov [.paeth_pc], ebx
mov ebx, ecx
sub ebx, [.paeth_a]
cmp ebx, 80000000h
sbb eax, eax
not eax
and eax, ebx
sub ebx, eax
sub ebx, eax
mov [.paeth_pa], ebx
mov ebx, ecx
sub ebx, [.paeth_b]
cmp ebx, 80000000h
sbb eax, eax
not eax
and eax, ebx
sub ebx, eax
sub ebx, eax
;mov [.paeth_pb], ebx
; select closest value
push edx
mov edx, [.paeth_b]
sub edx, [.paeth_a]
sub ebx, [.paeth_pa]
sbb ecx, ecx ; ecx = (pa > pb) ? 0xFFFFFFFF : 0
sbb eax, eax ; eax = (pa > pb) ? 0xFFFFFFFF : 0
and ecx, ebx ; ecx = (pa > pb) ? pb - pa : 0
and eax, edx ; eax = (pa > pb) ? b - a : 0
add ecx, [.paeth_pa] ; ecx = (pa > pb) ? pb : pa = min(pa,pb)
add eax, [.paeth_a] ; eax = (pa > pb) ? b : a
mov edx, [.paeth_c]
sub edx, eax
sub [.paeth_pc], ecx
sbb ebx, ebx ; ebx = (min(pa,pb) <= pc) ? 0 : 0xFFFFFFFF
and ebx, edx ; ebx = (min(pa,pb) <= pc) ? 0 : c - eax
add eax, ebx
pop edx
add [esi], al
pop ebx
sub edi, edx
add esi, 1
sub ebx, 1
jnz @b
pop ecx
.unfilter_paeth_done:
pop edx
jmp .next_scanline
.unfilter_none:
add esi, ebx
.next_scanline:
sub edx, [.row_increment]
jc .unfilter_done
cmp edx, [.starting_row]
jbe .unfilter_done
jmp .unfilter_loop_e
.unfilter_abort:
xor ecx, ecx
.unfilter_done:
; unfiltering done, now convert to raw data
; with deinterlacing if needed
pop esi
mov ebx, [.image]
mov eax, [.width]
call img._.get_scanline_len
mov [.row_distance], eax
mov eax, [.row_increment]
mul [.width]
sub eax, [.col_distance]
call img._.get_scanline_len
mov [.col_distance], eax
mov edi, [ebx + Image.Data]
mov eax, [.starting_row]
mul [.width]
add eax, [.starting_col]
call img._.get_scanline_len
add edi, eax
mov eax, ebx
mov ebx, [.size_rest]
mov [.size_rest], ecx
mov edx, [.height]
sub edx, [.starting_row]
mov [.j], edx
cmp [.color_type], 0
jz .grayscale2
cmp [.color_type], 2
jz .rgb2
cmp [.color_type], 3
jz .palette2
cmp [.color_type], 4
jz .grayscale_alpha2
.rgb_alpha2:
cmp [.bit_depth], 16
jz .rgb_alpha2_16bit
.rgb_alpha2.next:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
.rgb_alpha2.extloop:
macro init_block
{
push ebx
mov eax, [.col_increment]
mov edx, [.j]
cmp edx, [.block_height]
jb @f
mov edx, [.block_height]
@@:
mov ebx, [.i]
cmp ebx, [.block_width]
jb @f
mov ebx, [.block_width]
@@:
}
init_block
lea eax, [edi+eax*4]
push eax
.rgb_alpha2.innloop1:
push edi
mov ecx, ebx
.rgb_alpha2.innloop2:
mov al, [esi+2]
mov [edi], al
mov al, [esi+1]
mov [edi+1], al
mov al, [esi]
mov [edi+2], al
mov al, [esi+3]
mov [edi+3], al
add edi, 4
dec ecx
jnz .rgb_alpha2.innloop2
pop edi
add edi, [.row_distance]
dec edx
jnz .rgb_alpha2.innloop1
pop edi ebx
add esi, 4
mov eax, [.col_increment]
sub [.i], eax
ja .rgb_alpha2.extloop
add edi, [.col_distance]
mov eax, [.row_increment]
sub [.j], eax
ja .rgb_alpha2.next
jmp .convert_done
.rgb_alpha2_16bit:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
.rgb_alpha2_16bit.loop:
init_block
lea eax, [edi+eax*4]
push eax
.rgb_alpha2_16bit.innloop1:
push edi
mov ecx, ebx
.rgb_alpha2_16bit.innloop2:
mov ax, [esi+4]
convert_16_to_8
mov [edi], al
mov ax, [esi+2]
convert_16_to_8
mov [edi+1], al
mov ax, [esi]
convert_16_to_8
mov [edi+2], al
;mov ax, [esi+6]
;convert_16_to_8
;mov [edi+3], al
add edi, 4
dec ecx
jnz .rgb_alpha2_16bit.innloop2
pop edi
add edi, [.row_distance]
dec edx
jnz .rgb_alpha2_16bit.innloop1
pop edi ebx
add esi, 8
mov eax, [.col_increment]
sub [.i], eax
ja .rgb_alpha2_16bit.loop
add edi, [.col_distance]
mov eax, [.row_increment]
sub [.j], eax
ja .rgb_alpha2_16bit
jmp .convert_done
.grayscale2:
call .create_grayscale_palette
cmp [.bit_depth], 16
jz .grayscale2_16bit
.palette2:
cmp [.bit_depth], 1
jz .palette2_1bit
cmp [.bit_depth], 2
jz .palette2_2bit
cmp [.bit_depth], 4
jz .palette2_4bit
.palette2_8bit:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
.palette2_8bit.extloop:
init_block
add eax, edi
push eax
mov al, [esi]
inc esi
macro block_byte_innerloop extloop
{
local .l1
.l1:
mov ecx, ebx
rep stosb
sub edi, ebx
add edi, [.row_distance]
dec edx
jnz .l1
pop edi ebx
mov eax, [.col_increment]
sub [.i], eax
ja extloop
add edi, [.col_distance]
mov eax, [.row_increment]
sub [.j], eax
}
block_byte_innerloop .palette2_8bit.extloop
ja .palette2_8bit
jmp .convert_done
.palette2_4bit:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
mov [.shift], 0
.palette2_4bit.extloop:
init_block
add eax, edi
push eax
xor [.shift], 1
jz .palette2_4bit.shifted
mov al, [esi]
inc esi
shr al, 4
jmp @f
.palette2_4bit.shifted:
mov al, [esi-1]
and al, 0xF
@@:
block_byte_innerloop .palette2_4bit.extloop
ja .palette2_4bit
jmp .convert_done
.palette2_2bit:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
mov [.shift], 0
.palette2_2bit.extloop:
init_block
add eax, edi
push eax
mov cl, [.shift]
sub cl, 2
jns .palette2_2bit.shifted
mov cl, 6
mov al, [esi]
inc esi
shr al, cl
jmp @f
.palette2_2bit.shifted:
mov al, [esi-1]
shr al, cl
and al, 3
@@:
mov [.shift], cl
block_byte_innerloop .palette2_2bit.extloop
ja .palette2_2bit
jmp .convert_done
.palette2_1bit:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
mov [.shift], 0
.palette2_1bit.extloop:
init_block
add eax, edi
push eax
mov cl, [.shift]
dec cl
jns .palette2_1bit.shifted
mov cl, 7
mov al, [esi]
inc esi
shr al, cl
jmp @f
.palette2_1bit.shifted:
mov al, [esi-1]
shr al, cl
and al, 1
@@:
mov [.shift], cl
block_byte_innerloop .palette2_1bit.extloop
ja .palette2_1bit
jmp .convert_done
.grayscale2_16bit:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
.grayscale2_16bit.extloop:
init_block
add eax, edi
push eax
mov ax, [esi]
add esi, 2
convert_16_to_8
block_byte_innerloop .grayscale2_16bit.extloop
ja .grayscale2_16bit
jmp .convert_done
.rgb2:
cmp [.bit_depth], 16
jz .rgb2_16bit
.rgb2.next:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
.rgb2.extloop:
init_block
lea eax, [edi+eax*4]
push eax
.rgb2.innloop1:
push edi
mov ecx, ebx
.rgb2.innloop2:
mov eax, [esi]
bswap eax
mov al, 0xff
ror eax, 8
cmp eax, [.transparent_color]
jnz @f
and eax, 0x00ffffff
@@:
stosd
dec ecx
jnz .rgb2.innloop2
pop edi
add edi, [.row_distance]
dec edx
jnz .rgb2.innloop1
pop edi ebx
add esi, 3
mov eax, [.col_increment]
sub [.i], eax
ja .rgb2.extloop
add edi, [.col_distance]
mov eax, [.row_increment]
sub [.j], eax
ja .rgb2.next
jmp .convert_done
.rgb2_16bit:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
.rgb2_16bit.extloop:
init_block
lea eax, [eax*3]
add eax, edi
push eax
.rgb2_16bit.innloop1:
push edi
mov ecx, ebx
.rgb2_16bit.innloop2:
mov ax, [esi+4]
convert_16_to_8
mov [edi], al
mov ax, [esi+2]
convert_16_to_8
mov [edi+1], al
mov ax, [esi]
convert_16_to_8
mov [edi+2], al
add edi, 3
dec ecx
jnz .rgb2_16bit.innloop2
pop edi
add edi, [.row_distance]
dec edx
jnz .rgb2_16bit.innloop1
pop edi ebx
add esi, 6
mov eax, [.col_increment]
sub [.i], eax
ja .rgb2_16bit.extloop
add edi, [.col_distance]
mov eax, [.row_increment]
sub [.j], eax
ja .rgb2_16bit
jmp .convert_done
.grayscale_alpha2:
cmp [.bit_depth], 16
jz .grayscale_alpha2_16bit
.grayscale_alpha2.next:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
.grayscale_alpha2.extloop:
init_block
add eax, eax
add eax, edi
push eax
lodsw
macro block_word_innerloop extloop
{
local .l1
.l1:
mov ecx, ebx
rep stosw
sub edi, ebx
add edi, [.row_distance]
dec edx
jnz .l1
pop edi ebx
mov eax, [.col_increment]
sub [.i], eax
ja extloop
add edi, [.col_distance]
mov eax, [.row_increment]
sub [.j], eax
}
block_word_innerloop .grayscale_alpha2.extloop
ja .grayscale_alpha2.next
jmp .convert_done
.grayscale_alpha2_16bit:
sub ebx, 1
jc .convert_done
add esi, 1
sub ebx, [.scanline_len]
jc .convert_done
mov ecx, [.width]
sub ecx, [.starting_col]
mov [.i], ecx
.grayscale_alpha2_16bit.extloop:
init_block
add eax, eax
add eax, edi
push eax
lodsw
convert_16_to_8
mov ecx, eax
lodsw
convert_16_to_8
mov ah, cl
xchg al, ah
block_word_innerloop .grayscale_alpha2_16bit.extloop
ja .grayscale_alpha2_16bit
.convert_done:
; next interlace pass
.deinterlace_next:
mov eax, [.block_width]
cmp eax, [.block_height]
jz .deinterlace_dec_width
mov [.block_height], eax
mov [.col_increment], eax
dec [.col_increment_shift]
mov [.starting_row], eax
and [.starting_col], 0
jmp .deinterlace_loop
.deinterlace_dec_width:
shr eax, 1
jz .deinterlace_done
mov [.block_width], eax
mov [.starting_col], eax
add eax, eax
and [.starting_row], 0
mov [.row_increment], eax
bsf eax, eax
mov [.row_increment_shift], al
jmp .deinterlace_loop
.deinterlace_done:
mcall 68, 13, [.allocated]
mov esi, [.cur_chunk_ptr]
add esi, [.cur_chunk_size]
push [.length]
jmp .next_chunk
.deflate_callback:
mov ebp, [esp+4]
mov ebx, [esp+8]
xor eax, eax
mov esi, [.cur_chunk_size]
mov [ebx], esi
test esi, esi
jz .deflate_callback.ret
mov eax, [.cur_chunk_ptr]
mov ecx, [.length]
add esi, eax
mov [.cur_chunk_ptr], esi
and [.cur_chunk_size], 0
@@:
sub ecx, 12
jb .deflate_callback.ret
cmp dword [esi+4+4], 'IDAT'
jnz .deflate_callback.ret
mov edx, [esi+4]
bswap edx
sub ecx, edx
jb .deflate_callback.ret
add esi, 4+8
test edx, edx
jz @b
mov [.cur_chunk_size], edx
mov [.cur_chunk_ptr], esi
mov [.length], ecx
.deflate_callback.ret:
ret 8
.create_grayscale_palette:
push edi edx
mov edi, [eax + Image.Palette]
mov ecx, [.bit_depth]
cmp cl, 16
jnz @f
mov cl, 8
@@:
push 1
pop eax
shl eax, cl
xchg eax, ecx
mov edx, 0x010101
cmp al, 8
jz .graypal_common
mov edx, 0x111111
cmp al, 4
jz .graypal_common
mov edx, 0x555555
cmp al, 2
jz .graypal_common
mov edx, 0xFFFFFF
.graypal_common:
mov eax, 0xff000000
@@:
stosd
add eax, edx
loop @b
pop edx edi
ret
;endp
;;================================================================================================;;
align 4
proc img.encode.png uses ebx edx, _img:dword, _common:dword, _specific:dword
;;------------------------------------------------------------------------------------------------;;
;? Encode image into raw data in png format ;;
;;------------------------------------------------------------------------------------------------;;
;> [_img] = pointer to image ;;
;> [_common] = format independent options ;;
;> [_specific] = 0 / pointer to the structure of format specific options ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = 0 / pointer to encoded data ;;
;< ecx = error code / the size of encoded data ;;
;;================================================================================================;;
locals
encoded_file rd 1
encoded_file_size rd 1
simag png_image
endl
mov ebx,[_img]
mov eax,[ebx+Image.Type]
cmp eax,Image.bpp24
je @f
mov ecx,LIBIMG_ERROR_BIT_DEPTH
jmp .error
@@:
mov edx,ebp
sub edx,sizeof.png_image
mov dword[edx+png_image.version],PNG_IMAGE_VERSION
mov ecx,[ebx+Image.Width]
mov [edx+png_image.width],ecx ;Image width in pixels (columns)
mov eax,[ebx+Image.Height]
mov [edx+png_image.height],eax ;Image height in pixels (rows)
mov dword[edx+png_image.format],PNG_COLOR_TYPE_RGB
;mov dword[edx+png_image.flags],PNG_IMAGE_FLAG_???
imul ecx,3
mov edi,ecx
imul edi,[ebx+Image.Height]
cmp edi,4096
jge @f
mov edi,4096 ;minimum memory size
@@:
mov [encoded_file_size],edi
stdcall [mem.alloc],edi
test eax,eax
jnz @f
mov ecx,LIBIMG_ERROR_OUT_OF_MEMORY
jmp .error
@@:
mov [encoded_file],eax
mov edi,edx
sub edi,4
stdcall png_image_write_to_memory, edx,eax,edi,0,[ebx+Image.Data],ecx,0
mov eax,[encoded_file]
mov ecx,[encoded_file_size]
jmp .quit
.error:
xor eax,eax
.quit:
ret
endp