kolibrios/programs/develop/libraries/libs-dev/libimg/png/png.asm

1145 lines
25 KiB
NASM
Raw Normal View History

;;================================================================================================;;
;;//// 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 = 29*4
virtual at ebp - .localsize
.width dd ?
.height dd ?
.bit_depth dd ?
.color_type 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
; 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
; allocate image
push Image.bpp24
pop eax
cmp [.color_type], 2
jz @f
mov al, Image.bpp32
cmp [.color_type], 6
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
shr eax, 8
stosd
jmp @b
@@:
lodsd
dec esi
bswap eax
shr eax, 8
stosd
jmp .next_chunk
.idat:
jecxz .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
; 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:
}
.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, [eax*3]
add eax, edi
push eax
.rgb2.innloop1:
push edi
mov ecx, ebx
.rgb2.innloop2:
mov al, [esi+2]
mov [edi], al
mov al, [esi+1]
mov [edi+1], al
mov al, [esi]
mov [edi+2], al
add edi, 3
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:
call .create_grayscale_palette
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, edi
push eax
mov al, [esi]
add esi, 2
block_byte_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, edi
push eax
mov ax, [esi]
add esi, 4
convert_16_to_8
block_byte_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:
xor eax, eax
@@:
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