kolibrios/programs/develop/libraries/libs-dev/libimg/tiff/tiff.asm
Ivan Baravy a0a18277da libimg: tiff: Don't rely on EOI tag at the end of the strip.
Reference implementation (libtiff) has a workaround: precalculate data
size of the strip and don't rely on EOI tag of specific bit length.

This allow to read some invalid TIFF LZW images by my old scanner.

git-svn-id: svn://kolibrios.org@7735 a494cfbc-eb01-0410-851d-a64ba20cac60
2020-03-07 12:54:18 +00:00

1241 lines
27 KiB
NASM

;;================================================================================================;;
;;//// tiff.asm //// (c) dunkaist, 2011-2013 /////////////////////////////////////////////////////;;
;;================================================================================================;;
;; ;;
;; 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 'tiff.inc'
;;================================================================================================;;
proc img.is.tiff _data, _length ;/////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Determine if raw data could be decoded (is in tiff format) ;;
;;------------------------------------------------------------------------------------------------;;
;> _data = raw data as read from file/stream ;;
;> _length = data length ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = false / true ;;
;;================================================================================================;;
push esi
mov esi, [_data]
lodsw
cmp ax, word 'II'
je .little_endian
cmp ax, word 'MM'
je .big_endian
jmp .is_not_tiff
.little_endian:
lodsw
cmp ax, 0x002A
je .is_tiff
jmp .is_not_tiff
.big_endian:
lodsw
cmp ax, 0x2A00
je .is_tiff
.is_not_tiff:
pop esi
xor eax, eax
ret
.is_tiff:
pop esi
xor eax, eax
inc eax
ret
endp
;;================================================================================================;;
proc img.decode.tiff _data, _length, _options ;///////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Decode data into image if it contains correctly formed raw data in tiff format ;;
;;------------------------------------------------------------------------------------------------;;
;> _data = raw data as read from file/stream ;;
;> _length = data length ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = 0 (error) or pointer to image ;;
;;================================================================================================;;
locals
_endianness rd 1 ; 0 stands for LE, otherwise BE
retvalue rd 1 ; 0 (error) or pointer to image
endl
push ebx esi edi
mov esi, [_data]
lodsw
mov [_endianness], 0
cmp ax, word 'II'
seta byte[_endianness]
lodsw_
lodsd_
@@:
; push eax
stdcall tiff._.parse_IFD, [_data], eax, [_endianness]
; pop esi
; mov ebx, eax
; mov [retvalue], eax
; xor eax, eax
; lodsw_
; shl eax, 2
; lea eax, [eax*3]
; add esi, eax
; lodsd_
; test eax, eax
; jnz @b
; .quit:
; mov eax, [retvalue]
pop edi esi ebx
ret
endp
;;================================================================================================;;
proc img.encode.tiff _img, _p_length, _options ;//////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Encode image into raw data in tiff 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 tiff._.parse_IFD _data, _IFD, _endianness
locals
extended rd 1
retvalue rd 1
decompress rd 1
endl
push ebx edx edi
mov [retvalue], 0
invoke mem.alloc, sizeof.tiff_extra
test eax, eax
jz .quit
mov [extended], eax
mov ebx, eax
mov edi, eax
mov ecx, sizeof.tiff_extra/4
xor eax, eax
rep stosd
mov esi, [_IFD]
add esi, [_data]
lodsw_
movzx ecx, ax
@@:
push ecx
stdcall tiff._.parse_IFDE, [_data], [_endianness]
pop ecx
dec ecx
jnz @b
call tiff._.define_image_type
stdcall img.create, [ebx + tiff_extra.image_width], [ebx + tiff_extra.image_height], eax
test eax, eax
jz .quit
mov [retvalue], eax
mov edx, eax
mov [edx + Image.Extended], ebx
cmp [ebx+tiff_extra.compression], TIFF.COMPRESSION.UNCOMPRESSED
jne @f
mov [decompress], tiff._.decompress.uncompressed
jmp .decompressor_defined
@@:
cmp [ebx + tiff_extra.compression], TIFF.COMPRESSION.PACKBITS
jne @f
mov [decompress], tiff._.decompress.packbits
jmp .decompressor_defined
@@:
cmp [ebx + tiff_extra.compression], TIFF.COMPRESSION.LZW
jne @f
mov [decompress], tiff._.decompress.lzw
jmp .decompressor_defined
@@:
cmp [ebx + tiff_extra.compression], TIFF.COMPRESSION.CCITT1D
jne @f
mov [decompress], tiff._.decompress.ccitt1d
jmp .decompressor_defined
@@:
mov [decompress], 0
jmp .quit
.decompressor_defined:
push esi ; fixme!!
mov ecx, [edx + Image.Type]
cmp ecx, Image.bpp8i
je .bpp8i
cmp ecx, Image.bpp24
je .bpp24
cmp ecx, Image.bpp32
je .bpp32
cmp ecx, Image.bpp16
je .bpp16
cmp ecx, Image.bpp1
je .bpp1
cmp ecx, Image.bpp8g
je .bpp8g
cmp ecx, Image.bpp8a
je .bpp8a
cmp ecx, Image.bpp2i
je .bpp2i
cmp ecx, Image.bpp4i
je .bpp4i
jmp .quit
;error report!!
.bpp1:
.bpp1.palette:
mov edi, [edx+Image.Palette]
cmp [ebx + tiff_extra.photometric], TIFF.PHOTOMETRIC.BLACK_IS_ZERO
jne .bpp1.white_is_zero
.bpp1.black_is_zero:
mov [edi], dword 0xff000000
mov [edi + 4], dword 0xffffffff
jmp .common
.bpp1.white_is_zero:
mov [edi], dword 0xffffffff
mov [edi + 4], dword 0xff000000
jmp .common
.bpp2i:
stdcall tiff._.get_palette, 1 SHL 2, [_endianness]
jmp .common
.bpp4i:
stdcall tiff._.get_palette, 1 SHL 4, [_endianness]
jmp .common
.bpp8i:
stdcall tiff._.get_palette, 1 SHL 8, [_endianness]
jmp .common
.bpp8g:
jmp .common
.bpp8a:
jmp .common
.bpp16:
jmp .common
.bpp24:
jmp .common
.bpp32:
jmp .common
.common:
mov edi, [edx+Image.Data]
mov esi, [ebx+tiff_extra.strip_offsets]
mov edx, [ebx+tiff_extra.strip_byte_counts]
cmp [ebx + tiff_extra.strip_offsets_length], TIFF.IFDE_TYPE_LENGTH.SHORT
jne .l_x
cmp [ebx + tiff_extra.strip_byte_counts_length], TIFF.IFDE_TYPE_LENGTH.SHORT
jne .s_l
jmp .s_s
.l_x: cmp [ebx + tiff_extra.strip_byte_counts_length], TIFF.IFDE_TYPE_LENGTH.SHORT
jne .l_l
jmp .l_s
.s_s:
xor eax, eax
lodsw_
push esi
mov esi, eax
add esi, [_data]
xor ecx, ecx
mov cx, word[edx]
test [_endianness], 1
jz @f
xchg cl, ch
@@:
add edx, 2
stdcall [decompress], [retvalue]
pop esi
dec [ebx + tiff_extra.offsets_number]
jnz .s_s
jmp .decoded
.s_l:
xor eax, eax
lodsw_
push esi
mov esi, eax
add esi, [_data]
mov ecx, [edx]
test [_endianness], 1
jz @f
bswap ecx
@@:
add edx, 4
stdcall [decompress], [retvalue]
pop esi
dec [ebx + tiff_extra.offsets_number]
jnz .s_l
jmp .decoded
.l_s:
lodsd_
push esi
mov esi, eax
add esi, [_data]
xor ecx, ecx
mov cx, word[edx]
test [_endianness], 1
jz @f
xchg cl, ch
@@:
add edx, 2
stdcall [decompress], [retvalue]
pop esi
dec [ebx + tiff_extra.offsets_number]
jnz .l_s
jmp .decoded
.l_l:
lodsd_
push esi
mov esi, eax
add esi, [_data]
mov ecx, [edx]
test [_endianness], 1
jz @f
bswap ecx
@@:
add edx, 4
stdcall [decompress], [retvalue]
pop esi
dec [ebx + tiff_extra.offsets_number]
jnz .l_l
jmp .decoded
.decoded:
cmp [ebx + tiff_extra.planar_configuration], TIFF.PLANAR.PLANAR
jne .post.rgb_bgr
stdcall tiff._.planar_to_separate, [retvalue]
.post.rgb_bgr:
cmp [ebx + tiff_extra.samples_per_pixel], 3
jne .post.rgba_bgra
mov eax, [retvalue]
mov esi, [eax + Image.Data]
mov edi, [eax + Image.Data]
mov ecx, [eax + Image.Width]
imul ecx, [eax + Image.Height]
@@:
lodsw
movsb
mov byte[esi - 1], al
add edi, 2
dec ecx
jnz @b
jmp .post.predictor
.post.rgba_bgra:
cmp [ebx + tiff_extra.samples_per_pixel], 4
jne .post.bpp8a_to_bpp8g
mov eax, [retvalue]
mov esi, [eax + Image.Data]
mov edi, [eax + Image.Data]
mov ecx, [eax + Image.Width]
imul ecx, [eax + Image.Height]
@@:
lodsw
movsb
mov byte[esi - 1], al
add edi, 3
add esi, 1
dec ecx
jnz @b
jmp .post.predictor
.post.bpp8a_to_bpp8g:
mov eax, [retvalue]
cmp [eax + Image.Type], Image.bpp8a
jne .post.predictor
mov ebx, [retvalue]
stdcall tiff._.pack_8a, ebx
mov [ebx + Image.Type], Image.bpp8g
.post.predictor:
cmp [ebx + tiff_extra.predictor], 2 ; Horizontal differencing
jne .post.end
cmp [ebx + tiff_extra.image_width], 1
je .post.end
push ebx
mov edi, [ebx + tiff_extra.samples_per_pixel]
mov edx, edi
mov ebx, [retvalue]
.post.predictor.plane:
mov esi, [ebx + Image.Data]
sub esi, 1
add esi, edx
mov ecx, [ebx + Image.Height]
.post.predictor.line:
push ecx
mov ecx, [ebx + Image.Width]
sub ecx, 1
mov ah, byte[esi]
add esi, edi
@@:
mov al, byte[esi]
add al, ah
mov byte[esi], al
add esi, edi
shl eax, 8
dec ecx
jnz @b
pop ecx
dec ecx
jnz .post.predictor.line
dec edx
jnz .post.predictor.plane
pop ebx
.post.end:
.pop_quit:
pop esi
.quit:
pop edi edx ebx
mov eax, [retvalue]
ret
endp
proc tiff._.parse_IFDE _data, _endianness
push ebx edx edi
lodsw_
mov edx, tiff.IFDE_tag_table.begin
mov ecx, (tiff.IFDE_tag_table.end-tiff.IFDE_tag_table.begin)/8
.tag:
cmp ax, word[edx]
jne @f
lodsw_
jmp dword[edx + 4]
@@:
add edx, 8
dec ecx
jnz .tag
.tag_default: ; unknown/unsupported/unimportant
lodsw
lodsd
lodsd
jmp .quit ; just skip it
.tag_100: ; ImageWidth
cmp ax, TIFF.IFDE_TYPE.SHORT
jne @f
lodsd
xor eax, eax
lodsw_
mov [ebx + tiff_extra.image_width], eax
lodsw
jmp .quit
@@:
cmp ax, TIFF.IFDE_TYPE.LONG
jne @f
lodsd
lodsd_
mov [ebx + tiff_extra.image_width], eax
jmp .quit
@@:
jmp .quit
.tag_101: ; ImageHeight
cmp ax, TIFF.IFDE_TYPE.SHORT
jne @f
lodsd
xor eax, eax
lodsw_
mov [ebx + tiff_extra.image_height], eax
lodsw
jmp .quit
@@:
cmp ax, TIFF.IFDE_TYPE.LONG
jne @f
lodsd
lodsd_
mov [ebx + tiff_extra.image_height], eax
jmp .quit
@@:
jmp .quit
.tag_102: ; BitsPerSample
lodsd_
imul eax, TIFF.IFDE_TYPE_LENGTH.SHORT
cmp eax, 4
ja @f
xor eax, eax
lodsw_
mov [ebx + tiff_extra.bits_per_sample], eax
lodsw
jmp .quit
@@:
lodsd_
add eax, [_data]
push esi
mov esi, eax
xor eax, eax
lodsw_
pop esi
mov [ebx + tiff_extra.bits_per_sample], eax
jmp .quit
.tag_103: ; Compression
cmp ax, TIFF.IFDE_TYPE.SHORT
jne @f
lodsd
xor eax, eax
lodsw_
mov [ebx + tiff_extra.compression], eax
lodsw
jmp .quit
@@:
jmp .quit
.tag_106: ; PhotometricInterpretation
cmp ax, TIFF.IFDE_TYPE.SHORT
jne @f
lodsd
xor eax, eax
lodsw_
mov [ebx + tiff_extra.photometric], eax
lodsw
jmp .quit
@@:
jmp .quit
.tag_111: ; StripOffsets
cmp ax, TIFF.IFDE_TYPE.SHORT
jne @f
mov [ebx + tiff_extra.strip_offsets_length], TIFF.IFDE_TYPE_LENGTH.SHORT
jmp .tag_111.common
@@:
mov [ebx + tiff_extra.strip_offsets_length], TIFF.IFDE_TYPE_LENGTH.LONG
.tag_111.common:
lodsd_
mov [ebx + tiff_extra.offsets_number], eax
imul eax, [ebx+tiff_extra.strip_offsets_length]
cmp eax, 4
ja @f
mov [ebx + tiff_extra.strip_offsets], esi
lodsd
jmp .quit
@@:
lodsd_
add eax, [_data]
mov [ebx + tiff_extra.strip_offsets], eax
jmp .quit
.tag_115: ; SamplesPerPixel
lodsd_
imul eax, TIFF.IFDE_TYPE_LENGTH.SHORT
cmp eax, 4
ja @f
xor eax, eax
lodsw_
mov [ebx + tiff_extra.samples_per_pixel], eax
lodsw
jmp .quit
@@:
lodsd_
add eax, [_data]
movzx eax, word[eax]
jmp .quit
.tag_116: ; RowsPerStrip
cmp ax, TIFF.IFDE_TYPE.SHORT
jne @f
lodsd
xor eax, eax
lodsw_
mov [ebx + tiff_extra.rows_per_strip], eax
lodsw
jmp .quit
@@:
lodsd
lodsd_
mov [ebx + tiff_extra.rows_per_strip], eax
jmp .quit
.tag_117: ; StripByteCounts
cmp ax, TIFF.IFDE_TYPE.SHORT
jne @f
mov [ebx + tiff_extra.strip_byte_counts_length], TIFF.IFDE_TYPE_LENGTH.SHORT
jmp .tag_117.common
@@:
mov [ebx + tiff_extra.strip_byte_counts_length], TIFF.IFDE_TYPE_LENGTH.LONG
.tag_117.common:
lodsd_
imul eax, [ebx + tiff_extra.strip_byte_counts_length]
cmp eax, 4
ja @f
mov [ebx + tiff_extra.strip_byte_counts], esi
lodsd
jmp .quit
@@:
lodsd_
add eax, [_data]
mov [ebx + tiff_extra.strip_byte_counts], eax
jmp .quit
.tag_11c: ; Planar configuration
cmp ax, TIFF.IFDE_TYPE.SHORT
jne @f
lodsd
xor eax, eax
lodsw_
mov [ebx + tiff_extra.planar_configuration], eax
lodsw
@@:
jmp .quit
.tag_13d: ; Predictor
cmp ax, TIFF.IFDE_TYPE.SHORT
jne @f
lodsd
xor eax, eax
lodsw_
mov [ebx + tiff_extra.predictor], eax
lodsw
@@:
jmp .quit
.tag_140: ; ColorMap
lodsd
lodsd_
add eax, [_data]
mov [ebx + tiff_extra.palette], eax
jmp .quit
.tag_152: ; ExtraSamples
mov [ebx + tiff_extra.extra_samples], esi
mov ecx, [ebx + tiff_extra.extra_samples_number]
rep lodsw ; ignored
jmp .quit
.quit:
pop edi edx ebx
ret
endp
proc tiff._.define_image_type
xor eax, eax
cmp [ebx + tiff_extra.photometric], TIFF.PHOTOMETRIC.RGB
jne .palette_bilevel_grayscale
mov eax, -3
add eax, [ebx + tiff_extra.samples_per_pixel]
mov [ebx + tiff_extra.extra_samples_number], eax
dec eax
jns @f
mov eax, Image.bpp24
jmp .quit
@@:
dec eax
jns @f
mov eax, Image.bpp32
; mov [ebx + tiff_extra.extra_samples_number], 0
jmp .quit
@@:
.palette_bilevel_grayscale:
cmp [ebx + tiff_extra.palette], 0
je .bilevel_grayscale
cmp [ebx + tiff_extra.bits_per_sample], 2
jg @f
mov eax, Image.bpp2i
jmp .quit
@@:
cmp [ebx + tiff_extra.bits_per_sample], 4
jg @f
mov eax, Image.bpp4i
jmp .quit
@@:
cmp [ebx + tiff_extra.bits_per_sample], 8
jne @f
mov eax, Image.bpp8i
jmp .quit
@@:
jmp .quit
.bilevel_grayscale:
cmp [ebx + tiff_extra.bits_per_sample], 1
jg .grayscale
mov eax, Image.bpp1
jmp .quit
.grayscale:
cmp [ebx + tiff_extra.bits_per_sample], 8
jne .quit
cmp [ebx + tiff_extra.samples_per_pixel], 1
jne @f
mov eax, Image.bpp8g
jmp .quit
@@:
mov eax, Image.bpp8a
jmp .quit
.quit:
ret
endp
proc tiff._.decompress.uncompressed _image
rep movsb
ret
endp
proc tiff._.decompress.packbits _image
push edx
mov edx, ecx
.decode:
lodsb
dec edx
cmp al, 0x80
jb .different
jg .identical
test edx, edx
jz .quit
jmp .decode
.identical:
neg al
inc al
movzx ecx, al
dec edx
lodsb
rep stosb
test edx, edx
jnz .decode
jmp .quit
.different:
movzx ecx, al
inc ecx
sub edx, ecx
rep movsb
test edx, edx
jnz .decode
.quit:
pop edx
ret
endp
proc tiff._.decompress.ccitt1d _image
locals
current_tree rd 1
old_tree rd 1
width rd 1
height rd 1
width_left rd 1
is_makeup rd 1
endl
push ebx ecx edx esi
mov [is_makeup], 0
mov ebx, [_image]
push [ebx + Image.Height]
pop [height]
push [ebx + Image.Width]
pop [width]
mov edx, esi
.next_scanline:
push [width]
pop [width_left]
dec [height]
js .error
mov [current_tree], tiff._.huffman_tree_white.begin
mov [old_tree], tiff._.huffman_tree_black.begin
mov ebx, 0
mov ecx, 8
.next_run:
mov esi, [current_tree]
.branch:
lodsd
btr eax, 31
jnc .not_a_leaf
cmp eax, 63
seta byte[is_makeup]
ja @f
push [current_tree]
push [old_tree]
pop [current_tree]
pop [old_tree]
@@:
stdcall tiff._.write_run, [width_left], [current_tree]
mov [width_left], eax
test byte[is_makeup], 0x01
jnz .next_run
test eax, eax
jnz .next_run
jmp .next_scanline
.not_a_leaf:
test bh, bh
jnz @f
mov bl, byte[edx]
inc edx
mov bh, 8
@@:
test al, 0x02
jz .not_a_corner
dec bh
sal bl, 1
lahf
and ah, 0x03
cmp al, ah
jne .error
mov esi, [esi]
jmp .branch
.not_a_corner:
lodsd
dec bh
sal bl, 1
jc .branch
mov esi, eax
jmp .branch
.error:
.quit:
pop esi edx ecx ebx
ret
endp
struct lzw_ctx
bits_left dd ? ; in current byte (pointed to by [esi])
cur_shift dd ? ; 9 -- 12
shift_counter dd ? ; how many shifts of current length remained
table dd ?
last_table_entry dd ? ; zero based
next_table_entry dd ? ; where to place new entry
strip_len dd ?
old_code dd ?
ends
proc tiff._.lzw_get_code
mov edx, [ebx+lzw_ctx.cur_shift]
xor eax, eax
lodsb
mov ecx, [ebx+lzw_ctx.bits_left]
mov ch, cl
neg cl
add cl, 8
shl al, cl
mov cl, ch
shl eax, cl
sub edx, [ebx+lzw_ctx.bits_left]
; second_byte
cmp edx, 8
je .enough_zero
jb .enough_nonzero
sub edx, 8
lodsb
shl eax, 8
jmp .enough_nonzero
.enough_zero:
mov [ebx+lzw_ctx.bits_left], 8
lodsb
jmp .code_done
.enough_nonzero:
mov al, byte[esi]
neg edx
add edx, 8
mov ecx, edx
mov [ebx+lzw_ctx.bits_left], edx
shr eax, cl
.code_done:
dec [ebx+lzw_ctx.shift_counter]
jnz @f
mov ecx, [ebx+lzw_ctx.cur_shift]
add [ebx+lzw_ctx.cur_shift], 1
mov edx, 1
shl edx, cl
mov [ebx+lzw_ctx.shift_counter], edx
@@:
ret
endp
proc tiff._.add_string_to_table uses esi
mov esi, [ebx+lzw_ctx.table]
lea esi, [esi + eax*8 + 256]
mov ecx, dword[esi+4]
mov edx, [ebx+lzw_ctx.next_table_entry]
mov [edx], edi
lea eax, [ecx + 1]
mov [edx + 4], eax
add [ebx+lzw_ctx.next_table_entry], 8
add [ebx+lzw_ctx.last_table_entry], 1
mov esi, [esi]
cmp ecx, [ebx+lzw_ctx.strip_len]
cmovg ecx, [ebx+lzw_ctx.strip_len]
sub [ebx+lzw_ctx.strip_len], ecx
rep movsb
ret
endp
proc tiff._.init_code_table
cmp [ebx+lzw_ctx.table], 0
jne @f
invoke mem.alloc, 256 + 63488 ; 256 + (2^8 + 2^9 + 2^10 + 2^11 + 2^12)*(4+4)
test eax, eax
jz .quit
mov [ebx+lzw_ctx.table], eax
@@:
mov eax, [ebx+lzw_ctx.table]
mov [ebx+lzw_ctx.next_table_entry], eax
add [ebx+lzw_ctx.next_table_entry], 256 + (256*8) + 2*8
mov [ebx+lzw_ctx.cur_shift], 9
mov [ebx+lzw_ctx.shift_counter], 256-2 ; clear code, end of information
mov [ebx+lzw_ctx.last_table_entry], 257 ; 0--255, clear, eoi
push edi
mov ecx, 256
mov edi, [ebx+lzw_ctx.table]
mov edx, edi
add edi, 256
mov eax, 0
@@:
mov byte[edx], al
mov [edi], edx
add edi, 4
add edx, 1
add eax, 1
mov [edi], dword 1
add edi, 4
dec ecx
jnz @b
pop edi
.quit:
ret
endp
proc tiff._.decompress.lzw _image
locals
ctx lzw_ctx
endl
push ebx ecx edx esi
mov ecx, [ebx+tiff_extra.rows_per_strip]
mov ebx, [_image]
mov eax, [ebx+Image.Width]
call img._.get_scanline_len
imul eax, ecx
lea ebx, [ctx]
mov [ctx.strip_len], eax
mov [ctx.table], 0
mov [ctx.bits_left], 8
mov [ctx.cur_shift], 9
.begin:
cmp [ctx.strip_len], 0
jle .quit
stdcall tiff._.lzw_get_code
cmp eax, 0x101 ; end of information
je .quit
cmp eax, 0x100 ; clear code
jne .no_clear_code
call tiff._.init_code_table
; getnextcode
call tiff._.lzw_get_code
mov [ctx.old_code], eax
cmp eax, 0x101 ; end of information
je .quit
call tiff._.add_string_to_table
jmp .begin
.no_clear_code:
cmp eax, [ctx.last_table_entry]
ja .not_in_table
mov [ctx.old_code], eax
call tiff._.add_string_to_table
jmp .begin
.not_in_table:
xchg eax, [ctx.old_code]
call tiff._.add_string_to_table
cmp [ctx.strip_len], 0
jle @f
dec [ctx.strip_len]
mov byte[edi], al
add edi, 1
@@:
jmp .begin
.quit:
cmp [ctx.table], 0
je @f
invoke mem.free, [ctx.table]
@@:
pop esi edx ecx ebx
ret
endp
proc tiff._.write_run _width_left, _current_tree
push ebx
test eax, eax
jz .done
sub [_width_left], eax
js .error
cmp esi, tiff._.huffman_tree_black.begin
seta bh
cmp ecx, eax
ja .one_byte
.many_bytes:
mov bl, [edi]
@@:
shl bl, 1
or bl, bh
dec eax
dec ecx
jnz @b
mov [edi], bl
inc edi
mov ecx, eax
and eax, 0x07
shr ecx, 3
push eax
xor eax, eax
test bh, bh
jz @f
dec al
@@:
rep stosb
pop eax
mov ecx, 8
test eax, eax
jz .done
.one_byte:
mov bl, [edi]
@@:
shl bl, 1
or bl, bh
dec ecx
dec eax
jnz @b
mov byte[edi], bl
cmp [_width_left], 0
jne .done
mov bl, [edi]
shl bl, cl
mov byte[edi], bl
inc edi
.done:
mov eax, [_width_left]
jmp .quit
.error:
.quit:
pop ebx
ret
endp
proc tiff._.get_word _endianness
lodsw
test [_endianness], 1
jnz @f
ret
@@:
xchg al, ah
ret
endp
proc tiff._.get_dword _endianness
lodsd
test [_endianness], 1
jnz @f
ret
@@:
bswap eax
ret
ret
endp
proc tiff._.pack_8a _img
mov ebx, [_img]
mov esi, [ebx + Image.Data]
mov edi, esi
mov ecx, [ebx + Image.Width]
imul ecx, [ebx + Image.Height]
@@:
lodsw
stosb
dec ecx
jnz @b
ret
endp
proc tiff._.planar_to_separate _img
locals
pixels rd 1
tmp_image rd 1
channels rd 1
channel_padding rd 1
endl
pushad
mov ebx, [_img]
mov ecx, [ebx + Image.Width]
imul ecx, [ebx + Image.Height]
mov [pixels], ecx
cmp [ebx + Image.Type], Image.bpp24
je .bpp24
cmp [ebx + Image.Type], Image.bpp32
je .bpp32
; cmp [ebx + Image.Type], Image.bpp4
; je .bpp4
jmp .quit
.bpp24:
mov [channels], 3
mov [channel_padding], 2
lea eax, [ecx*3]
jmp .proceed
.bpp32:
mov [channels], 4
mov [channel_padding], 3
shl eax, 2
jmp .proceed
.bpp4:
mov [channels], 3
mov [channel_padding], 2
shr eax, 1
jmp .proceed
.proceed:
invoke mem.alloc, eax
test eax, eax
jz .quit
mov [tmp_image], eax
.channel:
mov esi, [ebx + Image.Data]
mov edi, [tmp_image]
mov ecx, [pixels]
mov eax, [channel_padding]
inc eax
sub eax, [channels]
add edi, eax
mov eax, [channels]
dec eax
imul eax, [pixels]
add esi, eax
@@:
lodsb
stosb
add edi, [channel_padding]
dec ecx
jnz @b
dec [channels]
jnz .channel
.quit:
mov eax, [tmp_image]
xchg [ebx + Image.Data], eax
invoke mem.free, eax
popad
ret
endp
proc tiff._.get_palette _num_colors, _endianness
mov esi, [ebx + tiff_extra.palette]
push ebx
mov ebx, 2
.bpp2.channel:
mov edi, ebx
add edi, [edx + Image.Palette]
mov ecx, [_num_colors]
@@:
lodsw_
shr eax, 8
stosb
add edi, 3
dec ecx
jnz @b
dec ebx
jns .bpp2.channel
pop ebx
ret
endp
;;================================================================================================;;
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
;;================================================================================================;;
;! Below is private data you should never use directly from your code ;;
;;================================================================================================;;
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
;;================================================================================================;;
tiff.IFDE_tag_table.begin:
.tag_100: dd 0x0100, tiff._.parse_IFDE.tag_100 ; image width
.tag_101: dd 0x0101, tiff._.parse_IFDE.tag_101 ; image height (this is called 'length' in spec)
.tag_102: dd 0x0102, tiff._.parse_IFDE.tag_102 ; bits per sample
.tag_103: dd 0x0103, tiff._.parse_IFDE.tag_103 ; compression
.tag_106: dd 0x0106, tiff._.parse_IFDE.tag_106 ; photometric interpretation
.tag_111: dd 0x0111, tiff._.parse_IFDE.tag_111 ; strip offsets
.tag_115: dd 0x0115, tiff._.parse_IFDE.tag_115 ; samples per pixel
.tag_116: dd 0x0116, tiff._.parse_IFDE.tag_116 ; rows per strip
.tag_117: dd 0x0117, tiff._.parse_IFDE.tag_117 ; strip byte counts
.tag_11c: dd 0x011c, tiff._.parse_IFDE.tag_11c ; planar configuration
.tag_13d: dd 0x013d, tiff._.parse_IFDE.tag_13d ; predictor
.tag_140: dd 0x0140, tiff._.parse_IFDE.tag_140 ; color map
.tag_152: dd 0x0152, tiff._.parse_IFDE.tag_152 ; extra samples
tiff.IFDE_tag_table.end:
include 'huffman.asm' ; huffman trees for ccitt1d compression method