;;================================================================================================;; ;;//// 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 . ;; ;; ;; ;;================================================================================================;; ;; ;; ;; 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.bpp8 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 shr 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.bpp8 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.bpp8 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 ;; ;;================================================================================================;; ;;////////////////////////////////////////////////////////////////////////////////////////////////;; ;;================================================================================================;; ;