kolibrios/programs/develop/libraries/libs-dev/libimg/gif/gif.asm
Ivan Baravy 201cf02d85 libimg: transparency fixes.
img.convert doesn't make opaque pixels transparent.
gif decoder considers palette pixels opaque.

git-svn-id: svn://kolibrios.org@8394 a494cfbc-eb01-0410-851d-a64ba20cac60
2020-12-13 17:22:19 +00:00

1585 lines
43 KiB
NASM

;;================================================================================================;;
;;//// gif.asm //// (c) mike.dld, 2007-2008 //////////////////////////////////////////////////////;;
;;================================================================================================;;
;;//// Partial (c) by Willow, Diamond and HidnPlayr //////////////////////////////////////////////;;
;;================================================================================================;;
;; ;;
;; 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/>. ;;
;; ;;
;;================================================================================================;;
;; ;;
;; References: ;;
;; 1. GIF LITE v3.0 (2004-2007) ;;
;; by Willow and Diamond ;;
;; svn://kolibrios.org/programs/media/gifview/trunk/gif_lite.inc ;;
;; 2. "GIF File Format Summary" ;;
;; from "Encyclopedia of Graphics File Formats" by O'Reilly ;;
;; http://www.fileformat.info/format/gif/ ;;
;; 3. "LZW and GIF explained" (1987) ;;
;; by Steve Blackstock, IEEE ;;
;; http://www.cis.udel.edu/~amer/CISC651/lzw.and.gif.explained.html ;;
;; 4. "Graphics Interchange Format (tm)" (June 15, 1987) ;;
;; by CompuServe Incorporated ;;
;; http://examples.oreilly.de/english_examples/gff/CDROM/GFF/VENDSPEC/GIF/GIF87A.TXT ;;
;; 5. "Graphics Interchange Format (sm)" (July 31, 1990) ;;
;; by CompuServe Incorporated ;;
;; http://examples.oreilly.de/english_examples/gff/CDROM/GFF/VENDSPEC/GIF/GIF89A.TXT ;;
;; ;;
;;================================================================================================;;
include 'gif.inc'
;;================================================================================================;;
proc img.is.gif _data, _length ;//////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Determine if raw data could be decoded (is in GIF format) ;;
;;------------------------------------------------------------------------------------------------;;
;> _data = raw data as read from file/stream ;;
;> _length = data length ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = false / true ;;
;;================================================================================================;;
cmp [_length], sizeof.gif.Header
jb .nope
mov eax, [_data]
cmp dword[eax], 'GIF8'
jne .nope
cmp word[eax + 4], '7a'
je .yep
cmp word[eax + 4], '9a'
je .yep
.nope:
xor eax, eax
ret
.yep:
xor eax, eax
inc eax
ret
endp
;;================================================================================================;;
proc img.decode.gif _data, _length, _options ;////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Decode data into image if it contains correctly formed raw data in GIF format ;;
;;------------------------------------------------------------------------------------------------;;
;> _data = raw data as read from file/stream ;;
;> _length = data length ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = 0 (error) or pointer to image ;;
;;================================================================================================;;
locals
max_color dd ?
cur_color_table_size dd ?
transparent_color dd ?
background_color dd ?
options_bgr dd ?
prev_palette dd ?
aux_palette dd ?
img dd ?
prev_img_data dd ?
aux_img_data dd ?
aux_img_type dd ?
prev_num_colors dd ?
main_img dd ?
global_color_table dd ?
global_color_table_size dd ?
endl
img.decode.gif.main_img equ main_img
img.decode.gif.prev_img_data equ prev_img_data
img.decode.gif.transparent_color equ transparent_color
img.decode.gif.background_color equ background_color
img.decode.gif._length equ _length
img.decode.gif.prev_num_colors equ prev_num_colors
img.decode.gif.prev_palette equ prev_palette
img.decode.gif.max_color equ max_color
img.decode.gif._data equ _data
img.decode.gif.aux_img_data equ aux_img_data
img.decode.gif.aux_img_type equ aux_img_type
img.decode.gif.aux_palette equ aux_palette
img.decode.gif.options_bgr equ options_bgr
; offset of _length parameter for child functions with ebp-based frame
; child saved ebp, return address, 3 saved registers, 15 local variables
img.decode.gif._length_child equ _length + 4 + 4 + 4*3 + 4*15
img.decode.gif.max_color_child equ ebp + 4 + 4 + 4*3
img.decode.gif.cur_color_table_size_child equ ebp + 4 + 4 + 4*3 + 4
push ebx esi edi
xor eax, eax
mov [img], eax
mov [main_img], eax
mov [prev_img_data], eax
mov [aux_img_data], eax
mov [aux_img_type], eax
mov [prev_palette], eax
mov [aux_palette], eax
; when no previous image is available, use background fill with 1-entry palette
inc eax
mov [prev_num_colors], eax
lea eax, [background_color]
mov [prev_palette], eax
; value for bgr color in transparent images
mov edx, 0xFFFFFF ; white bgr if no value given
mov ecx, [_options]
jecxz @f
cmp [ecx + ImageDecodeOptions.UsedSize], ImageDecodeOptions.BackgroundColor + 4
jb @f
mov edx, [ecx + ImageDecodeOptions.BackgroundColor]
@@:
mov [options_bgr], edx
mov dword [eax], edx
; guard against incorrect gif files without any color tables
; "If no color table is available at
; all, the decoder is free to use a system color table or a table of its own. In
; that case, the decoder may use a color table with as many colors as its
; hardware is able to support; it is recommended that such a table have black and
; white as its first two entries, so that monochrome images can be rendered
; adequately." (c) official gif documentation
mov [global_color_table], gif_default_palette
mov [global_color_table_size], 2
; img.is.gif is called by caller (img.decode)
; stdcall img.is.gif, [_data], [_length]
; or eax, eax
; jz .error
mov ebx, [_data]
sub [_length], sizeof.gif.Header
mov cl, [ebx + gif.Header.lsd.Packed]
add ebx, sizeof.gif.Header
; gif.LSD.Packed.GlobalColorTableFlag = 80h
; test cl, gif.LSD.Packed.GlobalColorTableFlag
; jz @f
test cl, cl
jns @f
mov [global_color_table], ebx
and cl, gif.LSD.Packed.SizeOfGlobalColorTableMask
; shr cl, gif.LSD.Packed.SizeOfGlobalColorTableShift ; here Shift = 0
push 2
pop eax
shl eax, cl
mov [global_color_table_size], eax
lea eax, [eax * 3]
sub [_length], eax
jbe .error ; there must be at least 1 additional byte after color table
movzx ecx, byte [ebx - sizeof.gif.Header + gif.Header.lsd.BackgroundColor]
lea ecx, [ecx*3]
mov ecx, [ebx + ecx] ; eax = xxBBGGRR, convert to Kolibri color
bswap ecx
shr ecx, 8
mov [background_color], ecx
add ebx, eax
@@:
; @@: cmp byte[ebx + gif.Block.Introducer], gif.Block.Introducer.Extension
; jne .next_image
; cmp byte[ebx + gif.Extension.Label], gif.Extension.Label.Comment
; jne .error
; add ebx, sizeof.gif.Extension
; stdcall ._.skip_data
; mov ebx, eax
; jmp @b
.next_image:
stdcall img._.new
or eax, eax
jz .error
mov edx, [img]
mov [eax + Image.Previous], edx
push sizeof.gif.LogicalScreenDescriptor
pop ecx
test edx, edx
jz @f
mov [edx + Image.Next], eax
xor ecx, ecx
@@:
push eax
mov [eax + Image.Type], Image.bpp8i
add ecx, sizeof.gif.Image
invoke mem.alloc, ecx
pop edx
or eax, eax
jz .error2
mov [edx + Image.Extended], eax
xor ecx, ecx
cmp [img], ecx
jnz @f
mov esi, [_data]
add esi, gif.Header.lsd
lea edi, [eax + sizeof.gif.Image]
mov cl, sizeof.gif.LogicalScreenDescriptor
rep movsb
mov [main_img], edx
@@:
mov [img], edx
stdcall ._.process_extensions
cmp al, gif.Block.Introducer.ImageDescriptor
jne .error
sub [_length], sizeof.gif.ImageDescriptor
jc .error
movzx eax, [ebx + gif.ImageDescriptor.Width]
movzx ecx, [ebx + gif.ImageDescriptor.Height]
push edx
stdcall img._.resize_data, [img], eax, ecx
pop edx
or eax, eax
jz .error
mov esi, ebx
mov edi, [edx + Image.Extended]
mov ecx, sizeof.gif.ImageDescriptor
rep movsb
mov edi, [edx + Image.Palette]
mov esi, [global_color_table]
mov ecx, [global_color_table_size]
test [ebx + gif.ImageDescriptor.Packed], gif.ID.Packed.LocalColorTableFlag
jz @f
lea esi, [ebx + sizeof.gif.ImageDescriptor]
mov cl, [ebx + gif.ImageDescriptor.Packed]
and cl, gif.ID.Packed.SizeOfLocalColorTableMask
; here Shift = 0
; shr cl, gif.ID.Packed.SizeOfLocalColorTableShift
push 2
pop eax
shl eax, cl
mov ecx, eax
lea eax, [eax*3]
add ebx, eax
sub [_length], eax
jbe .error ; because we load additional byte, check is 'jbe', not 'jc'
@@:
mov [cur_color_table_size], ecx
dec [cur_color_table_size]
@@:
lodsd
dec esi
bswap eax
mov al, 0xff ; opaque
ror eax, 8
stosd
loop @b
add ebx, sizeof.gif.ImageDescriptor
stdcall ._.process_image
push ebx
mov edx, [img]
push edx
stdcall ._.superimpose
pop edx
push edx
stdcall ._.dispose
pop edx
mov edx, [edx + Image.Previous]
test edx, edx
jz .nofreeprev
mov ebx, [edx + Image.Extended]
cmp [edx + Image.Delay], 0
jnz .nofreeprev
mov esi, [prev_palette]
cmp esi, [edx + Image.Palette]
jnz @f
mov ecx, [prev_num_colors]
stdcall ._.alloc_aux_palette
test eax, eax
jz .nofreeprev
mov [prev_palette], eax
@@:
mov esi, [prev_img_data]
cmp esi, [edx + Image.Data]
jnz .noprevdata
push 1
pop eax
cmp [edx + Image.Type], Image.bpp8i
jz @f
mov al, 3
@@:
cmp [aux_img_type], eax
jb .resetaux
mov edi, [aux_img_data]
imul eax, [edx + Image.Width]
imul eax, [edx + Image.Height]
xchg eax, ecx
rep movsb
jmp .noprevdata
.resetaux:
mov [aux_img_type], eax
mov eax, [aux_img_data]
test eax, eax
jz @f
invoke mem.free, eax
@@:
xor eax, eax
xchg eax, [edx + Image.Data]
mov [aux_img_data], eax
.noprevdata:
cmp edx, [main_img]
jnz @f
mov eax, [edx + Image.Next]
mov [main_img], eax
mov esi, [eax + Image.Extended]
mov edi, [edx + Image.Extended]
mov [edx + Image.Extended], esi
mov [eax + Image.Extended], edi
push sizeof.gif.Image
pop ecx
rep movsb
@@:
stdcall img.destroy.layer, edx
.nofreeprev:
pop ebx
test ebx, ebx
jz .ret
jmp .next_image
.error2:
mov [img], edx
.error:
mov eax, [img]
test eax, eax
jz .ret
cmp [main_img], eax
jnz @f
and [main_img], 0
@@:
stdcall img.destroy.layer, eax
.ret:
mov eax, [aux_img_data]
test eax, eax
jz @f
invoke mem.free, eax
@@:
mov eax, [aux_palette]
test eax, eax
jz @f
invoke mem.free, eax
@@:
mov eax, [main_img]
cmp [eax + Image.Next], 0
jz @f
or [eax + Image.Flags], Image.IsAnimated
@@:
pop edi esi ebx
ret
endp
;;================================================================================================;;
proc img.encode.gif _img, _p_length ;/////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Encode image into raw data in GIF format ;;
;;------------------------------------------------------------------------------------------------;;
;> _img = pointer to image ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = 0 (error) or pointer to encoded data ;;
;< _p_length = encoded data length ;;
;;================================================================================================;;
xor eax, eax
ret
endp
;;================================================================================================;;
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
;;================================================================================================;;
;! Below are private procs you should never call directly from your code ;;
;;================================================================================================;;
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
;;================================================================================================;;
;;================================================================================================;;
proc img.decode.gif._.process_extensions ;////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? --- TBD --- ;;
;;------------------------------------------------------------------------------------------------;;
;> ebx = raw image data ;;
;> edx = image data ;;
;;------------------------------------------------------------------------------------------------;;
;< --- TBD --- ;;
;;================================================================================================;;
mov esi, ebx
xor eax, eax
mov [edx + Image.Delay], eax
.next_block:
dec [img.decode.gif._length]
js .exit_err
lodsb ; load gif.Block.Introducer
cmp al, gif.Block.Introducer.Extension
jne .exit
.ext_block:
dec [img.decode.gif._length]
js .exit_err
lodsb ; load gif.Extension.Label
cmp al, gif.Extension.Label.GraphicsControl
je .graphics_control_ext
; cmp al, gif.Extension.Label.PlainText
; je .plain_text_ext
; cmp al, gif.Extension.Label.Comment
; je .comment_ext
; cmp al, gif.Extension.Label.Application
; je .application_ext
; skip all other extensions
.skip_ext:
dec [img.decode.gif._length]
js .exit_err
lodsb ; load BlockSize
.1:
test al, al
jz .next_block
sub [img.decode.gif._length], eax
jc .exit_err
add esi, eax
jmp .skip_ext
.graphics_control_ext:
dec [img.decode.gif._length]
js .exit_err
lodsb ; load BlockSize; must be sizeof.gif.GraphicsControlExtension
cmp al, sizeof.gif.GraphicsControlExtension
jnz .1
sub [img.decode.gif._length], eax
jc .exit_err
push edi
movzx edi, [esi + gif.GraphicsControlExtension.DelayTime]
mov [edx + Image.Delay], edi
mov edi, [edx + Image.Extended]
add edi, gif.Image.gce
mov ecx, eax
rep movsb
pop edi
jmp .skip_ext
.exit_err:
xor eax, eax
.exit:
mov ebx, esi
ret
endp
;;================================================================================================;;
proc img.decode.gif._.process_image ;/////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? --- TBD --- ;;
;;------------------------------------------------------------------------------------------------;;
;> ebx = raw image data ;;
;> edx = image data ;;
;;------------------------------------------------------------------------------------------------;;
;< --- TBD --- ;;
;;================================================================================================;;
locals
width dd ?
img_start dd ?
img_end dd ?
row_end dd ?
pass dd ?
codesize dd ?
compsize dd ?
workarea dd ?
block_ofs dd ?
bit_count dd ?
CC dd ?
EOI dd ?
endl
invoke mem.alloc, 16 * 1024
mov [workarea], eax
or eax, eax
jz .error
mov ecx, [edx + Image.Width]
mov [width], ecx
mov eax, [edx + Image.Height]
imul eax, ecx
mov [img_end], eax
inc eax
mov [row_end], eax
and [pass], 0
and dword [img.decode.gif.max_color_child], 0
mov eax, [edx + Image.Extended]
test [eax + gif.Image.info.Packed], gif.ID.Packed.InterleaceFlag
jz @f
mov [row_end], ecx
@@: mov esi, ebx
mov edi, [edx + Image.Data]
sub dword [img.decode.gif._length_child], 2
jc .error
movzx ecx, byte[esi]
inc esi
cmp cl, 12
jae .error
mov [codesize], ecx
inc [codesize]
xor eax, eax
lodsb ; eax - block_count
sub [img.decode.gif._length_child], eax
jc .error
add eax, esi
push edi
mov edi, [workarea]
mov [block_ofs], eax
mov [bit_count], 8
mov eax, 1
shl eax, cl
mov [CC], eax
mov ecx, eax
inc eax
mov [EOI], eax
mov eax, gif.Null shl 16
.filltable:
stosd
inc eax
loop .filltable
pop edi
mov [img_start], edi
add [img_end], edi
add [row_end], edi
.reinit:
mov edx, [EOI]
inc edx
push [codesize]
pop [compsize]
call .get_symbol
cmp eax, [CC]
je .reinit
call .output
.cycle:
movzx ebx, ax
call .get_symbol
cmp eax, [EOI]
je .end
cmp eax, edx
ja .error
je .notintable
cmp eax, [CC]
je .reinit
call .output
.add:
cmp edx, 0x00001000
jae .cycle
mov ecx, [workarea]
mov [ecx + edx * 4], ebx
inc edx
cmp edx, 0x1000
je .noinc
bsr ebx, edx
cmp ebx, [compsize]
jne .noinc
inc [compsize]
.noinc:
jmp .cycle
.notintable:
push eax
mov eax, ebx
call .output
push ebx
movzx eax, bx
call .output
pop ebx eax
jmp .add
.end:
mov edi, [img_end]
xor eax, eax
.exit:
cmp [workarea], 0
je @f
invoke mem.free, [workarea]
@@:
mov ebx, [block_ofs]
@@:
dec [img.decode.gif._length_child]
js @f
movzx eax, byte [ebx]
inc ebx
test eax, eax
jz .ret
sub [img.decode.gif._length_child], eax
jc @f
add ebx, eax
jmp @b
.error:
cmp [workarea], 0
je @f
invoke mem.free, [workarea]
@@: xor ebx, ebx
.ret:
ret
;;------------------------------------------------------------------------------------------------;;
img.decode.gif._.process_image.get_symbol:
mov ecx, [compsize]
push ecx
xor eax, eax
.shift:
dec [bit_count]
jns .loop1
inc esi
cmp esi, [block_ofs]
jb .noblock
push eax
xor eax, eax
sub [img.decode.gif._length_child], 1
jc .error_eof
lodsb
test eax, eax
jnz .nextbl
.error_eof:
add esp, 12
jmp img.decode.gif._.process_image.error
.nextbl:
sub [img.decode.gif._length_child], eax
jc .error_eof
add eax, esi
mov [block_ofs], eax
pop eax
.noblock:
mov [bit_count], 7
.loop1:
ror byte[esi], 1
rcr eax,1
loop .shift
pop ecx
rol eax, cl
.exit:
xor ecx, ecx
retn
;;------------------------------------------------------------------------------------------------;;
img.decode.gif._.process_image.output:
push esi eax edx
mov edx, [workarea]
.next:
pushw [edx + eax * 4]
mov ax, [edx + eax * 4 + 2]
inc ecx
cmp ax, gif.Null
jnz .next
shl ebx, 16
mov bx, [esp]
.loop2:
pop ax
cmp al, byte [img.decode.gif.cur_color_table_size_child]
jbe @f ; guard against incorrect GIFs
mov al, 0
@@: cmp al, byte [img.decode.gif.max_color_child]
jbe @f
mov [img.decode.gif.max_color_child], al
@@: stosb
cmp edi, [row_end]
jb .norowend
mov eax, [width]
push eax
sub edi, eax
add eax, eax
cmp [pass], 3
je @f
add eax, eax
cmp [pass], 2
je @f
add eax, eax
@@: add edi, eax
pop eax
cmp edi, [img_end]
jb .nextrow
mov edi, [img_start]
inc [pass]
cmp [pass], 4
je .done
add edi, eax
cmp [pass], 3
je @f
add edi, eax
cmp [pass], 2
je @f
add edi, eax
add edi, eax
@@:
.nextrow:
add eax, edi
mov [row_end], eax
xor eax, eax
.norowend:
cmp edi, [img_end]
jz .done
loop .loop2
pop edx eax esi
retn
.done:
lea esp, [esp+(ecx-1)*2]
pop edx eax esi eax
jmp img.decode.gif._.process_image.exit
endp
;;================================================================================================;;
proc img.decode.gif._.is_logical_screen ;/////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Determines whether GIF image occupies the whole logical screen ;;
;;------------------------------------------------------------------------------------------------;;
;> eax = extended image data ;;
;> ebx = main image ;;
;;------------------------------------------------------------------------------------------------;;
;< ZF set <=> image area equals logical screen ;;
;;================================================================================================;;
mov ebx, [ebx + Image.Extended]
cmp [eax + gif.Image.info.Left], 0
jnz @f
cmp [eax + gif.Image.info.Top], 0
jnz @f
mov cx, [eax + gif.Image.info.Width]
cmp cx, [ebx + sizeof.gif.Image + gif.LogicalScreenDescriptor.ScreenWidth]
jnz @f
mov cx, [eax + gif.Image.info.Height]
cmp cx, [ebx + sizeof.gif.Image + gif.LogicalScreenDescriptor.ScreenHeight]
@@: retn
endp
main_img equ img.decode.gif.main_img
transparent_color equ img.decode.gif.transparent_color
background_color equ img.decode.gif.background_color
prev_num_colors equ img.decode.gif.prev_num_colors
prev_palette equ img.decode.gif.prev_palette
max_color equ img.decode.gif.max_color
prev_img_data equ img.decode.gif.prev_img_data
_data equ img.decode.gif._data
aux_img_data equ img.decode.gif.aux_img_data
aux_img_type equ img.decode.gif.aux_img_type
aux_palette equ img.decode.gif.aux_palette
;;================================================================================================;;
proc img.decode.gif._.superimpose ;///////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? --- TBD --- ;;
;;------------------------------------------------------------------------------------------------;;
;> edx = image data ;;
;;------------------------------------------------------------------------------------------------;;
;< --- TBD --- ;;
;;================================================================================================;;
mov ebx, [main_img]
mov eax, [edx + Image.Extended]
or [transparent_color], -1 ; no transparent color
test byte [eax + gif.Image.gce.Packed], 1
jz @f
movzx ecx, byte [eax + gif.Image.gce.ColorIndex]
mov [transparent_color], ecx
cmp edx, ebx
jnz .has_transparency
shl ecx, 2
add ecx, [edx + Image.Palette]
push eax
mov eax, [img.decode.gif.options_bgr]
mov dword [background_color], eax
mov dword [ecx], eax
pop eax
@@:
call img.decode.gif._.is_logical_screen
jnz .has_transparency
; image is not transparent, so keep it as is
retn
.has_transparency:
; image has transparent areas, we must superimpose it on the previous
mov ecx, [prev_num_colors]
cmp ecx, 0x100
ja .superimpose_on_rgb
; create common palette
sub esp, 3FCh
push eax
mov edi, esp
push ecx
mov esi, [prev_palette]
rep movsd
pop ecx
mov esi, [edx + Image.Palette]
xor ebx, ebx
mov edi, esp
sub esp, 100h
.create_palette_loop:
push ecx
lodsd
cmp ebx, [transparent_color]
jz .nochange
cmp ebx, ecx
jae @f
cmp eax, [edi+ebx*4]
jz .nochange
@@:
push edi
repnz scasd
pop edi
jnz .increase_palette
sub ecx, [esp]
not ecx ; cl = index of new color in current palette
jmp .palette_common
.increase_palette:
mov ecx, [esp]
test ch, ch
jnz .output_to_rgb
inc dword [esp]
mov [edi+ecx*4], eax
jmp .palette_common
.nochange:
mov ecx, ebx
.palette_common:
mov [ebx+esp+4], cl
pop ecx
inc ebx
cmp ebx, [max_color]
jbe .create_palette_loop
mov [max_color], ecx
; if image occupies only part of logical screen, allocate memory for full logical screen
mov ebx, [main_img]
mov eax, [edx + Image.Extended]
mov esi, [edx + Image.Data]
call img.decode.gif._.is_logical_screen
jz @f
and [edx + Image.Data], 0
push edx
movzx eax, [ebx + sizeof.gif.Image + gif.LogicalScreenDescriptor.ScreenHeight]
push eax
movzx eax, [ebx + sizeof.gif.Image + gif.LogicalScreenDescriptor.ScreenWidth]
stdcall img._.resize_data, edx, eax
pop edx
test eax, eax
jz .palette_nomem
@@:
; copy final palette to Image.Palette
push esi esi
mov esi, edi
mov edi, [edx + Image.Palette]
mov ecx, [max_color]
dec [max_color]
rep movsd
mov esi, [prev_img_data]
mov edi, [edx + Image.Data]
; do superimpose, [esp] -> source data, esi -> prev image data
; (NULL if previous image is filled with background color), esp+8 -> correspondence between
; used palette and final palette, edi -> destination data
mov ebx, [edx + Image.Extended]
; first Top rows are copied from [prev_img_data] or filled with bgr
movzx ecx, [ebx + gif.Image.info.Top]
cmp ecx, [edx + Image.Height]
jb @f
mov ecx, [edx + Image.Height]
@@:
push ecx
imul ecx, [edx + Image.Width]
call .rep_movsb_or_stosb
pop ecx
; convert rows
sub ecx, [edx + Image.Height]
neg ecx
push ecx
cmp cx, [ebx + gif.Image.info.Height]
jbe @f
mov cx, [ebx + gif.Image.info.Height]
@@:
jecxz .norows
.convert_rows:
push ecx
movzx ecx, [ebx + gif.Image.info.Left]
cmp ecx, [edx + Image.Width]
jb @f
mov ecx, [edx + Image.Width]
@@:
push ecx
call .rep_movsb_or_stosb
pop ecx
sub ecx, [edx + Image.Width]
neg ecx
push ecx edx
mov edx, [esp+16] ; source data
cmp cx, [ebx + gif.Image.info.Width]
jbe @f
mov cx, [ebx + gif.Image.info.Width]
@@:
jecxz .norowsi
.rowsloop:
movzx eax, byte [edx]
inc edx
cmp eax, [transparent_color]
jz .rows_transparent
mov al, [eax+esp+24]
stosb
call .lodsb
jmp @f
.rows_transparent:
call .lodsb
stosb
@@:
loop .rowsloop
.norowsi:
pop edx ecx
sub cx, [ebx + gif.Image.info.Width]
jbe @f
call .rep_movsb_or_stosb
@@:
movzx eax, [ebx + gif.Image.info.Width]
add [esp+8], eax
pop ecx
loop .convert_rows
.norows:
pop ecx
sub cx, [ebx + gif.Image.info.Height]
jbe @f
imul ecx, [edx + Image.Width]
call .rep_movsb_or_stosb
@@:
; free old image data if we have allocated new copy
pop esi esi
cmp esi, [edx + Image.Data]
jz @f
invoke mem.free, esi
@@:
; cleanup stack and return
add esp, 500h
retn
.palette_nomem:
mov [edx + Image.Data], esi
jmp @b
.output_to_rgb:
pop ecx
add esp, 500h
; compose two palette-based images to one RGB image
xor esi, esi
xchg esi, [edx + Image.Data]
push esi
mov ebx, [_data]
push [edx + Image.Palette]
mov byte [edx + Image.Type], Image.bpp24
push edx
movzx eax, [ebx + gif.Header.lsd.ScreenHeight]
push eax
movzx eax, [ebx + gif.Header.lsd.ScreenWidth]
stdcall img._.resize_data, edx, eax
pop edx
test eax, eax
jz .convrgb_nomem
push esi
mov edi, [edx + Image.Data]
mov esi, [prev_img_data]
mov ebx, [edx + Image.Extended]
; first Top rows are copied from [prev_img_data] or filled with bgr
movzx ecx, [ebx + gif.Image.info.Top]
cmp ecx, [edx + Image.Height]
jb @f
mov ecx, [edx + Image.Height]
@@:
push ecx
imul ecx, [edx + Image.Width]
call .convrgb_prev
pop ecx
; convert rows
sub ecx, [edx + Image.Height]
neg ecx
push ecx
cmp cx, [ebx + gif.Image.info.Height]
jbe @f
mov cx, [ebx + gif.Image.info.Height]
@@:
jecxz .convrgb_norows
.convrgb_convert_rows:
push ecx
movzx ecx, [ebx + gif.Image.info.Left]
cmp ecx, [edx + Image.Width]
jb @f
mov ecx, [edx + Image.Width]
@@:
push ecx
call .convrgb_prev
pop ecx
sub ecx, [edx + Image.Width]
neg ecx
push ecx edx
mov edx, [esp+16] ; source data
cmp cx, [ebx + gif.Image.info.Width]
jbe @f
mov cx, [ebx + gif.Image.info.Width]
@@:
jecxz .convrgb_norowsi
.convrgb_rowsloop:
movzx eax, byte [edx]
inc edx
cmp eax, [transparent_color]
jz .convrgb_rows_transparent
shl eax, 2
add eax, [esp+20] ; source palette
mov eax, [eax]
stosw
shr eax, 16
stosb
call .convrgb_lodsb
jmp @f
.convrgb_rows_transparent:
call .convrgb_lodsb
stosw
shr eax, 16
stosb
@@:
loop .convrgb_rowsloop
.convrgb_norowsi:
pop edx ecx
sub cx, [ebx + gif.Image.info.Width]
jbe @f
call .convrgb_prev
@@:
movzx eax, [ebx + gif.Image.info.Width]
add [esp+8], eax
pop ecx
loop .convrgb_convert_rows
.convrgb_norows:
pop ecx
sub cx, [ebx + gif.Image.info.Height]
jbe @f
imul ecx, [edx + Image.Width]
call .convrgb_prev
@@:
; free old image data
pop esi esi ;esi
invoke mem.free;, esi
retn
.convrgb_nomem:
pop esi esi
retn
.superimpose_on_rgb:
; previous image is RGB, new image has transparent areas
xor esi, esi
xchg esi, [edx + Image.Data]
push esi
mov ebx, [_data]
push [edx + Image.Palette]
mov byte [edx + Image.Type], Image.bpp24
push edx
movzx eax, [ebx + gif.Header.lsd.ScreenHeight]
push eax
movzx eax, [ebx + gif.Header.lsd.ScreenWidth]
stdcall img._.resize_data, edx, eax
pop edx
test eax, eax
jz .rgb_nomem
push esi
mov edi, [edx + Image.Data]
mov esi, [prev_img_data]
mov ebx, [edx + Image.Extended]
; first Top rows are copied from [prev_img_data] or filled with bgr
movzx ecx, [ebx + gif.Image.info.Top]
cmp ecx, [edx + Image.Height]
jb @f
mov ecx, [edx + Image.Height]
@@:
push ecx
lea ecx, [ecx*3]
imul ecx, [edx + Image.Width]
rep movsb
pop ecx
; convert rows
sub ecx, [edx + Image.Height]
neg ecx
push ecx
cmp cx, [ebx + gif.Image.info.Height]
jbe @f
mov cx, [ebx + gif.Image.info.Height]
@@:
jecxz .rgb_norows
.rgb_convert_rows:
push ecx
movzx ecx, [ebx + gif.Image.info.Left]
cmp ecx, [edx + Image.Width]
jb @f
mov ecx, [edx + Image.Width]
@@:
push ecx
lea ecx, [ecx*3]
rep movsb
pop ecx
sub ecx, [edx + Image.Width]
neg ecx
push ecx edx
mov edx, [esp+16] ; source data
cmp cx, [ebx + gif.Image.info.Width]
jbe @f
mov cx, [ebx + gif.Image.info.Width]
@@:
jecxz .rgb_norowsi
.rgb_rowsloop:
movzx eax, byte [edx]
inc edx
cmp eax, [transparent_color]
jz .rgb_rows_transparent
shl eax, 2
add eax, [esp+20] ; source palette
mov eax, [eax]
stosw
shr eax, 16
stosb
add esi, 3
jmp @f
.rgb_rows_transparent:
movsb
movsb
movsb
@@:
loop .rgb_rowsloop
.rgb_norowsi:
pop edx ecx
sub cx, [ebx + gif.Image.info.Width]
jbe @f
lea ecx, [ecx*3]
rep movsb
@@:
movzx eax, [ebx + gif.Image.info.Width]
add [esp+8], eax
pop ecx
loop .rgb_convert_rows
.rgb_norows:
pop ecx
sub cx, [ebx + gif.Image.info.Height]
jbe @f
imul ecx, [edx + Image.Width]
lea ecx, [ecx*3]
rep movsb
@@:
; free old image data
pop esi esi ;esi
invoke mem.free;, esi
retn
.rgb_nomem:
pop esi esi
retn
.lodsb:
xor eax, eax
test esi, esi
jz @f
lodsb
@@: retn
.rep_movsb_or_stosb:
test esi, esi
jz .rmos1
rep movsb
jmp .rmos2
.rmos1: xor eax, eax ; background index in final palette is 0 in bgr mode
rep stosb
.rmos2: retn
.convrgb_prev:
jecxz .convrgb_noprev
test esi, esi
jz .convrgb_prev_bgr
@@:
xor eax, eax
lodsb
shl eax, 2
add eax, [prev_palette]
mov eax, [eax]
stosw
shr eax, 16
stosb
loop @b
retn
.convrgb_prev_bgr:
@@:
mov eax, [background_color]
stosw
shr eax, 16
stosb
loop @b
.convrgb_noprev:
retn
.convrgb_lodsb:
xor eax, eax
test esi, esi
jz @f
lodsb
shl eax, 2
add eax, [prev_palette]
mov eax, [eax]
retn
@@: mov eax, [background_color]
retn
endp
;;================================================================================================;;
proc img.decode.gif._.dispose ;///////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? --- TBD --- ;;
;;------------------------------------------------------------------------------------------------;;
;> edx = image data ;;
;;------------------------------------------------------------------------------------------------;;
;< --- TBD --- ;;
;;================================================================================================;;
mov ebx, [edx + Image.Extended]
mov al, [ebx + gif.Image.gce.Packed]
shr al, 2
and al, 7
cmp al, 2
jz .background
cmp al, 3
jz .previous
; don't dispose - set prev_img and related vars to current image
mov eax, [edx + Image.Data]
mov [prev_img_data], eax
cmp [edx + Image.Type], Image.bpp8i
jnz @f
mov eax, [max_color]
inc eax
mov [prev_num_colors], eax
mov eax, [edx + Image.Palette]
mov [prev_palette], eax
retn
@@:
or [prev_num_colors], -1
and [prev_palette], 0
.previous:
retn
.background:
cmp [prev_img_data], 0
jz .bgr_full
mov ebx, [main_img]
mov eax, [edx + Image.Extended]
call img.decode.gif._.is_logical_screen
jnz @f
.bgr_full:
xor eax, eax
mov [prev_img_data], eax
inc eax
mov [prev_num_colors], eax
lea eax, [background_color]
mov [prev_palette], eax
retn
@@:
cmp [prev_num_colors], 0x100
ja .rgb
mov eax, [background_color]
mov edi, [prev_palette]
mov ecx, [prev_num_colors]
repnz scasd
jz .palette_ok
cmp [prev_num_colors], 0x100
jz .convert_rgb
push 1
pop eax
stdcall img.decode.gif._.alloc_aux_img
test eax, eax
jz .previous
mov ecx, [prev_num_colors]
mov esi, [prev_palette]
call img.decode.gif._.alloc_aux_palette
test eax, eax
jz .previous
mov [prev_palette], eax
mov eax, [background_color]
stosd
mov eax, [prev_num_colors] ; eax = index of background color
inc [prev_num_colors]
jmp .bpp8_common
.palette_ok:
push 1
pop eax
stdcall img.decode.gif._.alloc_aux_img
test eax, eax
jz .previous
sub edi, [prev_palette]
shr edi, 2
lea eax, [edi-1] ; eax = index of background color
.bpp8_common:
push eax
mov ebx, [_data]
mov esi, [prev_img_data]
mov edi, [aux_img_data]
mov [prev_img_data], edi
cmp esi, edi
jz @f
movzx ecx, [ebx + gif.Header.lsd.ScreenWidth]
movzx eax, [ebx + gif.Header.lsd.ScreenHeight]
imul ecx, eax
push edi
rep movsb
pop edi
@@:
movzx esi, [ebx + gif.Header.lsd.ScreenHeight]
movzx eax, [ebx + gif.Header.lsd.ScreenWidth]
mov edx, [edx + Image.Extended]
movzx ecx, [edx + gif.Image.info.Top]
sub esi, ecx
jbe .bpp8_ret
imul ecx, eax
add edi, ecx
cmp si, [edx + gif.Image.info.Height]
jb @f
mov si, [edx + gif.Image.info.Height]
@@:
movzx ecx, [edx + gif.Image.info.Left]
sub eax, ecx
jbe .bpp8_ret
add edi, ecx
cmp ax, [edx + gif.Image.info.Width]
jb @f
mov ax, [edx + gif.Image.info.Width]
@@:
xchg eax, ecx
movzx edx, [ebx + gif.Header.lsd.ScreenWidth]
sub edx, ecx
pop eax
@@:
push ecx
rep stosb
pop ecx
add edi, edx
dec esi
jnz @b
push eax
.bpp8_ret:
pop eax
retn
.convert_rgb:
push 3
pop eax
stdcall img.decode.gif._.alloc_aux_img
test eax, eax
jz .previous
or [prev_num_colors], -1
mov ebx, [_data]
mov esi, [prev_img_data]
mov edi, [aux_img_data]
mov [prev_img_data], edi
movzx ecx, [ebx + gif.Header.lsd.ScreenWidth]
movzx eax, [ebx + gif.Header.lsd.ScreenHeight]
imul ecx, eax
push edx
xor edx, edx
xchg edx, [prev_palette]
add edi, ecx
add esi, ecx
add edi, ecx
add edi, ecx
@@:
dec esi
movzx eax, byte [esi]
mov eax, [eax*4+edx]
sub edi, 3
mov [edi], ax
shr eax, 16
mov [edi+2], al
loop @b
pop edx
movzx esi, [ebx + gif.Header.lsd.ScreenHeight]
movzx eax, [ebx + gif.Header.lsd.ScreenWidth]
mov edx, [edx + Image.Extended]
movzx ecx, [edx + gif.Image.info.Top]
sub esi, ecx
jbe .convert_rgb_ret
imul ecx, eax
lea ecx, [ecx*3]
add edi, ecx
cmp si, [edx + gif.Image.info.Height]
jb @f
mov si, [edx + gif.Image.info.Height]
@@:
movzx ecx, [edx + gif.Image.info.Left]
sub eax, ecx
jbe .convert_rgb_ret
lea ecx, [ecx*3]
add edi, ecx
cmp ax, [edx + gif.Image.info.Width]
jb @f
mov ax, [edx + gif.Image.info.Width]
@@:
xchg eax, ecx
movzx edx, [ebx + gif.Header.lsd.ScreenWidth]
sub edx, ecx
mov eax, [background_color]
lea edx, [edx*3]
.convert_rgb_loop:
push ecx
@@:
stosw
shr eax, 16
stosb
loop @b
pop ecx
add edi, edx
dec esi
jnz .convert_rgb_loop
.convert_rgb_ret:
retn
.rgb:
push 3
pop eax
stdcall img.decode.gif._.alloc_aux_img
test eax, eax
jz .previous
or [prev_num_colors], -1
and [prev_palette], 0
mov ebx, [_data]
mov esi, [prev_img_data]
mov edi, [aux_img_data]
mov [prev_img_data], edi
cmp esi, edi
jz @f
movzx ecx, [ebx + gif.Header.lsd.ScreenHeight]
push ecx
movzx eax, [ebx + gif.Header.lsd.ScreenWidth]
imul ecx, eax
lea ecx, [ecx*3]
push edi
rep movsb
pop edi
pop esi
mov edx, [edx + Image.Extended]
movzx ecx, [edx + gif.Image.info.Top]
sub esi, ecx
jbe .rgb_ret
imul ecx, eax
lea ecx, [ecx*3]
add edi, ecx
cmp si, [edx + gif.Image.info.Height]
jb @f
mov si, [edx + gif.Image.info.Height]
@@:
movzx ecx, [edx + gif.Image.info.Left]
sub eax, ecx
jbe .rgb_ret
lea ecx, [ecx*3]
add edi, ecx
cmp ax, [edx + gif.Image.info.Width]
jb @f
mov ax, [edx + gif.Image.info.Width]
@@:
xchg eax, ecx
movzx edx, [ebx + gif.Header.lsd.ScreenWidth]
sub edx, ecx
mov eax, [background_color]
lea edx, [edx*3]
.rgb_loop:
push ecx
@@:
stosw
shr eax, 16
stosb
loop @b
pop ecx
add edi, edx
dec esi
jnz .rgb_loop
.rgb_ret:
retn
endp
;;================================================================================================;;
proc img.decode.gif._.alloc_aux_img ;/////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Allocate auxiliary memory for previous image ;;
;;------------------------------------------------------------------------------------------------;;
;> eax = image type: 1 = bpp8, 3 = bpp24 ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = [aux_img_data] ;;
;;================================================================================================;;
cmp [aux_img_type], eax
jae @f
push edx eax
movzx ecx, [ebx + sizeof.gif.Image + gif.LogicalScreenDescriptor.ScreenWidth]
mul ecx
movzx ecx, [ebx + sizeof.gif.Image + gif.LogicalScreenDescriptor.ScreenHeight]
mul ecx
invoke mem.realloc, [aux_img_data], eax
pop ecx edx
test eax, eax
jz @f
mov [aux_img_type], ecx
mov [aux_img_data], eax
@@: retn
endp
;;================================================================================================;;
proc img.decode.gif._.alloc_aux_palette ;/////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Allocate and fill aux_palette ;;
;;------------------------------------------------------------------------------------------------;;
;> esi -> palette, ecx = palette size ;;
;;------------------------------------------------------------------------------------------------;;
;< [aux_palette] set ;;
;;================================================================================================;;
mov eax, [aux_palette]
test eax, eax
jnz @f
push edx ecx
invoke mem.alloc, 0x400
pop ecx edx
test eax, eax
jz .ret
mov [aux_palette], eax
@@:
mov edi, eax
rep movsd
.ret:
retn
endp
restore main_img
restore transparent_color
restore background_color
restore prev_num_colors
restore prev_palette
restore max_color
restore prev_img_data
restore _data
restore aux_img_data
restore aux_img_type
restore aux_palette
;;================================================================================================;;
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
;;================================================================================================;;
;! Below is private data you should never use directly from your code ;;
;;================================================================================================;;
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
;;================================================================================================;;
;