c87db09b6e
git-svn-id: svn://kolibrios.org@7279 a494cfbc-eb01-0410-851d-a64ba20cac60
1145 lines
25 KiB
NASM
1145 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 = 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 |