;;================================================================================================;;
;;//// bmp.asm //// (c) mike.dld, 2007-2008, (c) diamond, 2009 ///////////////////////////////////;;
;;================================================================================================;;
;;                                                                                                ;;
;; This file is part of Common development libraries (Libs-Dev).                                  ;;
;;                                                                                                ;;
;; Libs-Dev is free software: you can redistribute it and/or modify it under the terms of the GNU ;;
;; Lesser General Public License as published by the Free Software Foundation, either version 2.1 ;;
;; of the License, or (at your option) any later version.                                         ;;
;;                                                                                                ;;
;; Libs-Dev is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without  ;;
;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  ;;
;; Lesser General Public License for more details.                                                ;;
;;                                                                                                ;;
;; You should have received a copy of the GNU Lesser General Public License along with Libs-Dev.  ;;
;; If not, see <http://www.gnu.org/licenses/>.                                                    ;;
;;                                                                                                ;;
;;================================================================================================;;
;;                                                                                                ;;
;; References:                                                                                    ;;
;;   1. "Microsoft Windows Bitmap File Format Summary"                                            ;;
;;      from "Encyclopedia of Graphics File Formats" by O'Reilly                                  ;;
;;      http://www.fileformat.info/format/bmp/                                                    ;;
;;                                                                                                ;;
;;================================================================================================;;


include 'bmp.inc'

;;================================================================================================;;
;;proc img.is.bmp _data, _length ;////////////////////////////////////////////////////////////////;;
img.is.bmp:
;;------------------------------------------------------------------------------------------------;;
;? Determine if raw data could be decoded (is in BMP format)                                      ;;
;;------------------------------------------------------------------------------------------------;;
;> _data = raw data as read from file/stream                                                      ;;
;> _length = data length                                                                          ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = false / true                                                                             ;;
;;================================================================================================;;
; test 1 (length of data): data must contain FileHeader and required fields from InfoHeader
	cmp	dword [esp+8], sizeof.bmp.FileHeader + 12
	jb	.nope
; test 2: signature
	mov	eax, [esp+4]
	cmp	word [eax], 'BM'
	je	.yep

  .nope:
	xor	eax, eax
	ret	8

  .yep:
	xor	eax, eax
	inc	eax
	ret	8
;endp

;;================================================================================================;;
proc img.decode.bmp _data, _length, _options ;////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Decode data into image if it contains correctly formed raw data in BMP format                  ;;
;;------------------------------------------------------------------------------------------------;;
;> _data = raw data as read from file/stream                                                      ;;
;> _length = data length                                                                          ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = 0 (error) or pointer to image                                                            ;;
;;================================================================================================;;
locals
  length_rest dd ?
  img dd ?
  bTopDown db ?
  bIsIco db ?
endl
img.decode.bmp.length_rest equ length_rest
	mov	[bIsIco], 0
.common: ; common place for BMP and ICO

	push	ebx esi edi

	mov	ebx, [_data]
	cmp	[bIsIco], 0
	jnz	@f
	add	ebx, sizeof.bmp.FileHeader
	sub	[_length], sizeof.bmp.FileHeader
   @@:

	mov	eax, [ebx + bmp.InfoHeader.Size]
; sanity check: file length must be greater than size of headers
	cmp	[_length], eax
	jbe	.error

	mov	[bTopDown], 0

	cmp	eax, 12
	jz	.old1
	cmp	eax, 40
	jz	.normal
	cmp	eax, 56
	jnz	.error
; convert images with <= 8 bpp to 8bpp, other - to 32 bpp
.normal:
	m2m	eax, Image.bpp8
	cmp	byte [ebx + 14], 8	; bit count
	jbe	@f
	mov	al, Image.bpp32
@@:
	push	eax
	mov	eax, [ebx + 8]	;[ebx + bmp.InfoHeader.Height]
	test	eax, eax
	jns	@f
	inc	[bTopDown]
	neg	eax
@@:
	cmp	[bIsIco], 0	; for icons Height is two times larger than image height
	jz	@f
	shr	eax, 1
@@:
	pushd	eax
	pushd	[ebx + 4]	;[ebx + bmp.InfoHeader.Width]
	jmp	.create
.old1:
	m2m	eax, Image.bpp8
	cmp	byte [ebx + 10], 8	; bit count
	jbe	@f
	mov	al, Image.bpp32
@@:
	push	eax
	movsx	eax, word [ebx + 6]	;[ebx + bmp.InfoHeader.OldHeight]
	test	eax, eax
	jns	@f
	inc	[bTopDown]
	neg	eax
@@:
	cmp	[bIsIco], 0	; for icons Height is two times larger than image height
	jz	@f
	shr	eax, 1
@@:
	push	eax
	movzx	eax, word [ebx + 4]	;[ebx + bmp.InfoHeader.OldWidth]
	push	eax
.create:
	call	img.create

	or	eax, eax
	jz	.error
	mov	[img], eax
	mov	edx, eax

	invoke	mem.alloc, sizeof.bmp.Image
	or	eax, eax
	jz	.error.free
	mov	[edx + Image.Extended], eax
	push	eax
	mov	edi, eax
	mov	ecx, sizeof.bmp.Image/4
	xor	eax, eax
	rep	stosd
	pop	edi
	push	edi
	mov	esi, ebx
	mov	ecx, [ebx]	;[ebx + bmp.InfoHeader.Size]
	cmp	ecx, 12
	jz	.old2
	rep	movsb
	jmp	.decode
.old2:
	movsd	; Size
	movzx	eax, word [esi]	; OldWidth -> Width
	stosd
	movsx	eax, word [esi+2]	; OldHeight -> Height
	stosd
	lodsd	; skip OldWidth+OldHeight
	movsd	; Planes+BitCount
.decode:

	pop	edi
	cmp	[bIsIco], 0
	jnz	@f
	mov	edi, [_length]
	add	edi, sizeof.bmp.FileHeader
	mov	esi, [ebx - sizeof.bmp.FileHeader + bmp.FileHeader.OffBits]
	jmp	.offset_calculated
@@:
	xor	esi, esi
	mov	cl, byte [edi + bmp.Image.info.BitCount]
	cmp	cl, 8
	ja	@f
	inc	esi
	add	cl, 2
	shl	esi, cl
@@:
	add	esi, [edi + bmp.Image.info.Size]
	mov	edi, [_length]
.offset_calculated:
	sub	edi, esi
	jbe	.error.free
	add	esi, [_data]

	mov	eax, [edx + Image.Extended]
	mov	eax, [eax + bmp.Image.info.Compression]
	cmp	eax, bmp.BI_RGB
	jne	@f
	stdcall ._.rgb
	jmp	.decoded
    @@: cmp	eax, bmp.BI_RLE8
	jne	@f
	cmp	word [ebx + 14], 8 ;bmp.InfoHeader.BitCount
	jnz	.error.free
	stdcall ._.rle
	jmp	.decoded
    @@: cmp	eax, bmp.BI_RLE4
	jne	@f
	cmp	word [ebx + 14], 4
	jnz	.error.free
	stdcall ._.rle
	jmp	.decoded
    @@: cmp	eax, bmp.BI_BITFIELDS
	jne	.error.free
	stdcall ._.bitfields
	jmp	.decoded
; BI_JPEG and BI_PNG constants are not valid values for BMP file,
; they are intended for WinAPI
;    @@: cmp	eax, bmp.BI_JPEG
;	jne	@f
;	stdcall ._.jpeg
;	jmp	.decoded
;    @@: cmp	eax, bmp.BI_PNG
;	jne	.error
;	stdcall ._.png

  .decoded:
	or	eax, eax
	jz	@f
  .error.free:
	stdcall img.destroy, [img]
	jmp	.error

    @@:
	cmp	[bTopDown], 0
	jnz	@f
	stdcall img.flip, [img], FLIP_VERTICAL
    @@:
	mov	eax, [img]
	mov	ecx, [length_rest]	; return length for ICO code
	cmp	[bIsIco], 0
	jz	@f
	mov	[esp + 4], esi	; return pointer to end-of-data for ICO code
    @@:
	pop	edi esi ebx
	ret

  .error:
	xor	eax, eax
	pop	edi esi ebx
	ret
endp

;;================================================================================================;;
proc img.encode.bmp _img, _p_length, _options ;///////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Encode image into raw data in BMP 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.bmp._.rgb ;///////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? --- TBD ---                                                                                    ;;
;;------------------------------------------------------------------------------------------------;;
;> ebx = raw image data                                                                           ;;
;> edx = image data                                                                               ;;
;;------------------------------------------------------------------------------------------------;;
;< --- TBD ---                                                                                    ;;
;;================================================================================================;;
	mov	ecx, [edx + Image.Extended]
	mov	[ecx + bmp.Image.info.AlphaMask], 0

	movzx	eax, [ecx + bmp.Image.info.BitCount]
	cmp	eax, 32
	je	.32bpp
	cmp	eax, 24
	je	.24bpp
	cmp	eax, 16
	je	.16bpp
	cmp	eax, 8
	je	.8bpp
	cmp	eax, 4
	je	.4bpp
	cmp	eax, 1
	je	.1bpp
	jmp	.error

;;------------------------------------------------------------------------------------------------;;

img.decode.bmp._.rgb.32bpp:
	mov	[ecx + bmp.Image.info.RedMask],   00000000111111110000000000000000b ; 8-0-0
	mov	[ecx + bmp.Image.info.GreenMask], 00000000000000001111111100000000b ; 0-8-0
	mov	[ecx + bmp.Image.info.BlueMask],  00000000000000000000000011111111b ; 0-0-8
	stdcall img.decode.bmp._.bitfields
	ret

;;------------------------------------------------------------------------------------------------;;

img.decode.bmp._.rgb.24bpp:
	mov	eax, [edx + Image.Width]
	lea	eax, [eax*3 + 3]
	and	eax, not 3
	mov	ecx, [edx + Image.Height]
	imul	eax, ecx
	sub	edi, eax
	jb	img.decode.bmp._.rgb.error
	mov	[img.decode.bmp.length_rest], edi
	mov	edi, [edx + Image.Data]

  .next_line:
	push	ecx edx
	mov	ecx, [edx + Image.Width]
	xor	edx, edx

  .next_line_pixel:
	movsd
	dec	esi
	inc	edx
	dec	ecx
	jnz	.next_line_pixel

	and	edx, 0x03
	add	esi, edx
	pop	edx ecx
	dec	ecx
	jnz	.next_line

	jmp	img.decode.bmp._.rgb.exit

;;------------------------------------------------------------------------------------------------;;

img.decode.bmp._.rgb.16bpp:
	mov	[ecx + bmp.Image.info.RedMask],   00000000000000000111110000000000b ; 5-0-0
	mov	[ecx + bmp.Image.info.GreenMask], 00000000000000000000001111100000b ; 0-5-0
	mov	[ecx + bmp.Image.info.BlueMask],  00000000000000000000000000011111b ; 0-0-5
	stdcall img.decode.bmp._.bitfields
	ret

;;------------------------------------------------------------------------------------------------;;

img.decode.bmp._.rgb.8bpp:
	mov	eax, [edx + Image.Width]
	add	eax, 3
	call	img.decode.bmp._.rgb.prepare_palette
	jc	img.decode.bmp._.rgb.error

  .next_line:
	push	ecx
	mov	ecx, [edx + Image.Width]
	mov	eax, ecx
	neg	eax
	and	eax, 3
	rep	movsb
	add	esi, eax
	pop	ecx
	dec	ecx
	jnz	.next_line

	jmp	img.decode.bmp._.rgb.exit

;;------------------------------------------------------------------------------------------------;;

img.decode.bmp._.rgb.4bpp:
	mov	eax, [edx + Image.Width]
	add	eax, 7
	shr	eax, 1
	call	img.decode.bmp._.rgb.prepare_palette
	jc	img.decode.bmp._.rgb.error

  .next_line:
	push	ecx edx
	mov	ecx, [edx + Image.Width]

  .next_line_dword:
	push	ecx
	lodsd
	bswap	eax
	xchg	edx, eax
	mov	ecx, 32 / 4

  .next_pixel:
	rol	edx, 4
	mov	al, dl
	and	al, 0x0000000F
	stosb
	dec	dword[esp]
	jz	@f
	dec	ecx
	jnz	.next_pixel

    @@: pop	ecx
	or	ecx, ecx
	jnz	.next_line_dword

	pop	edx ecx
	dec	ecx
	jnz	.next_line

	jmp	img.decode.bmp._.rgb.exit

;;------------------------------------------------------------------------------------------------;;

img.decode.bmp._.rgb.1bpp:
	mov	eax, [edx + Image.Width]
	add	eax, 31
	shr	eax, 3
	call	img.decode.bmp._.rgb.prepare_palette
	jc	img.decode.bmp._.rgb.error

  .next_line:
	push	ecx edx
	mov	ecx, [edx + Image.Width]

  .next_line_dword:
	push	ecx
	lodsd
	bswap	eax
	xchg	edx, eax
	mov	ecx, 32 / 1

  .next_pixel:
	rol	edx, 1
	mov	al, dl
	and	al, 0x00000001
	stosb
	dec	dword[esp]
	jz	@f
	dec	ecx
	jnz	.next_pixel

    @@: pop	ecx
	or	ecx, ecx
	jnz	.next_line_dword

	pop	edx ecx
	dec	ecx
	jnz	.next_line

	jmp	img.decode.bmp._.rgb.exit

;;------------------------------------------------------------------------------------------------;;

  img.decode.bmp._.rgb.exit:
	xor	eax, eax
	ret

  img.decode.bmp._.rgb.error:
	or	eax, -1
	ret

img.decode.bmp._.rgb.prepare_palette:
	and	eax, not 3
	mov	ecx, [edx + Image.Height]
	imul	eax, ecx
	sub	edi, eax
	jb	.ret
	mov	[img.decode.bmp.length_rest], edi
	push	esi
	sub	esi, ebx
	jc	.ret.pop
	sub	esi, [ebx + bmp.InfoHeader.Size]
	jc	.ret.pop
	mov	eax, esi
	mov	edi, [edx + Image.Palette]
	push	ecx
	mov	ecx, 256
	mov	esi, [ebx + bmp.InfoHeader.Size]
	cmp	esi, 12
	jz	.old
	shr	eax, 2
	add	esi, ebx
	cmp	ecx, eax
	jb	@f
	mov	ecx, eax
@@:
	rep	movsd
	jmp	.common
.old:
	add	esi, ebx
@@:
	movsd
	dec	esi
	sub	eax, 3
	jbe	@f
	sub	ecx, 1
	jnz	@b
@@:
.common:
	pop	ecx
	mov	edi, [edx + Image.Data]
	clc
.ret.pop:
	pop	esi
.ret:
	ret
endp

;;================================================================================================;;
proc img.decode.bmp._.rle ;///////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? --- TBD ---                                                                                    ;;
;;------------------------------------------------------------------------------------------------;;
;> ebx = raw image data                                                                           ;;
;> edx = image data                                                                               ;;
;;------------------------------------------------------------------------------------------------;;
;< --- TBD ---                                                                                    ;;
;;================================================================================================;;
locals
  scanline_len	dd ?
  marker_x	dd ?
  marker_y	dd ?
  abs_mode_addr dd ?
  enc_mode_addr dd ?
  height	dd ?
endl

	mov	[abs_mode_addr], .absolute_mode.rle8
	mov	[enc_mode_addr], .encoded_mode.rle8
	cmp	[ebx + bmp.InfoHeader.Compression], bmp.BI_RLE4
	jne	@f
	mov	[abs_mode_addr], .absolute_mode.rle4
	mov	[enc_mode_addr], .encoded_mode.rle4
    @@:

	push	edi
	xor	eax, eax	; do not check file size in .prepare_palette
	push	ebp
	mov	ebp, [ebp]	; set parent stack frame
	call	img.decode.bmp._.rgb.prepare_palette
	pop	ebp
	pop	ecx	; ecx = rest bytes in file
	jc	.error

	mov	eax, [edx + Image.Width]
	mov	[scanline_len], eax
	mov	eax, [edx + Image.Height]
	mov	[height], eax
	xor	eax, eax
	mov	[marker_x], eax
	mov	[marker_y], eax
	mov	edi, [edx + Image.Data]

  .next_run:
	sub	ecx, 1
	jc	.eof
	xor	eax, eax
	lodsb
	or	al, al
	jz	.escape_mode
	jmp	[enc_mode_addr]

  .escape_mode:
	sub	ecx, 1
	jc	.eof
	lodsb
	cmp	al, 0
	je	.end_of_scanline
	cmp	al, 1
	je	.exit
	cmp	al, 2
	je	.offset_marker
	jmp	[abs_mode_addr]

  .end_of_scanline: ; 0
	sub	edi, [marker_x]
	add	edi, [scanline_len]
	mov	[marker_x], 0
	mov	eax, [marker_y]
	inc	eax
	mov	[marker_y], eax
	cmp	eax, [height]
	jb	.next_run
	jmp	.exit

  .offset_marker: ; 2: dx, dy
	sub	ecx, 2
	jc	.eof
	lodsb
	mov	edx, [marker_x]
	add	edx, eax
	cmp	edx, [scanline_len]
	jae	.exit
	mov	[marker_x], edx
	add	edi, eax
	lodsb
	mov	edx, [marker_y]
	add	edx, eax
	cmp	edx, [height]
	jae	.exit
	mov	[marker_y], edx
	imul	eax, [scanline_len]
	add	edi, eax
	jmp	.next_run

  .encoded_mode.rle8: ; N: b1 * N
	call	.fix_marker
	sub	ecx, 1
	jc	.eof
	lodsb
	push	ecx
	mov	ecx, edx
	rep	stosb
	pop	ecx
	jmp	.check_eoi

  .absolute_mode.rle8: ; N: b1 .. bN
	call	.fix_marker
	cmp	ecx, edx
	jae	@f
	mov	edx, ecx
    @@:
	push	ecx
	mov	ecx, edx
	rep	movsb
	pop	ecx
	sub	ecx, edx
	jz	.eof
	test	edx, 1
	jz	.check_eoi
	sub	ecx, 1
	jc	.eof
	inc	esi
  .check_eoi:
	mov	eax, [marker_y]
	cmp	eax, [height]
	jb	.next_run
	jmp	.exit

  .encoded_mode.rle4: ; N: b1 * N
	call	.fix_marker
	sub	ecx, 1
	jc	.eof
	movzx	eax, byte [esi]
	inc	esi
	push	ecx
	mov	ecx, eax
	and	eax, 0xF
	shr	ecx, 4
    @@:
	dec	edx
	js	@f
	mov	[edi], cl
	dec	edx
	js	@f
	mov	[edi+1], al
	add	edi, 2
	jmp	@b
    @@:
	pop	ecx
	jmp	.check_eoi

  .absolute_mode.rle4: ; N: b1 .. bN
	call	.fix_marker
	lea	eax, [edx+1]
	shr	eax, 1
	cmp	ecx, eax
	jbe	@f
	lea	edx, [ecx*2]
    @@:
	push	ecx edx
    @@: dec	edx
	js	@f
	lodsb
	mov	cl, al
	shr	al, 4
	and	cl, 0xF
	stosb
	dec	edx
	js	@f
	mov	[edi], cl
	inc	edi
	jmp	@b
    @@: pop	eax ecx
	and	eax, 0x03
	jp	.check_eoi
	sub	ecx, 1
	jc	.eof
	inc	esi
	jmp	.check_eoi

  .fix_marker:
	mov	edx, eax
	add	eax, [marker_x]
	mov	[marker_x], eax
    @@:
	sub	eax, [scanline_len]
	jle	@f
	mov	[marker_x], eax
	push	eax
	mov	eax, [marker_y]
	inc	eax
	mov	[marker_y], eax
	cmp	eax, [height]
	pop	eax
	jb	@b
	sub	edx, eax
    @@:
        retn

  .exit:
  .eof:
	xor	eax, eax
	ret

  .error:
	or	eax, -1
	ret
endp

;;================================================================================================;;
proc img.decode.bmp._.bitfields ;/////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? --- TBD ---                                                                                    ;;
;;------------------------------------------------------------------------------------------------;;
;> ebx = raw image data                                                                           ;;
;> edx = image data                                                                               ;;
;;------------------------------------------------------------------------------------------------;;
;< --- TBD ---                                                                                    ;;
;;================================================================================================;;
locals
  shift   bmp.RgbByteQuad
  unshift bmp.RgbByteQuad
  mask	  bmp.RgbQuad
  delta   dd ?
endl

	mov	[delta], 4
	mov	eax, [edx + Image.Extended]
	cmp	[eax + bmp.Image.info.BitCount], 32
	je	@f
	cmp	[eax + bmp.Image.info.BitCount], 16
	jne	.error
	mov	[delta], 2
    @@:
	mov	ecx, [edx + Image.Width]
	imul	ecx, [edx + Image.Height]
	imul	ecx, [delta]
	sub	edi, ecx
	jb	.error
	mov	ecx, [ebp]	; use parent stack frame
	mov	[ecx + img.decode.bmp.length_rest - ebp], edi	; !

	push	esi
	mov	esi, eax

	mov	ecx, [esi + bmp.Image.info.RedMask]
	call	.calc_shift
	mov	[shift.Red], al
	mov	[mask.Red], ecx
	call	.calc_unshift
	mov	[unshift.Red], al
	mov	ecx, [esi + bmp.Image.info.GreenMask]
	call	.calc_shift
	mov	[shift.Green], al
	mov	[unshift.Green], al
	mov	[mask.Green], ecx
	call	.calc_unshift
	mov	[unshift.Green], al
	mov	ecx, [esi + bmp.Image.info.BlueMask]
	call	.calc_shift
	mov	[shift.Blue], al
	mov	[unshift.Blue], al
	mov	[mask.Blue], ecx
	call	.calc_unshift
	mov	[unshift.Blue], al
	mov	ecx, [esi + bmp.Image.info.AlphaMask]
	call	.calc_shift
	mov	[shift.Alpha], al
	mov	[unshift.Alpha], al
	mov	[mask.Alpha], ecx
	call	.calc_unshift
	mov	[unshift.Alpha], al

	mov	edi, [edx + Image.Data]
	pop	esi

;;------------------------------------------------------------------------------------------------;;

	mov	ecx, [edx + Image.Height]

  .next_line:
	push	ecx
	mov	ecx, [edx + Image.Width]
	
  .next_pixel:
	push	ecx

	mov	eax, [esi]
	mov	cl, [shift.Blue]
	shr	eax, cl
	and	eax, [mask.Blue]
	mov	cl, [unshift.Blue]
	shl	eax, cl
	stosb

	mov	eax, [esi]
	mov	cl, [shift.Green]
	shr	eax, cl
	and	eax, [mask.Green]
	mov	cl, [unshift.Green]
	shl	eax, cl
	stosb

	mov	eax, [esi]
	mov	cl, [shift.Red]
	shr	eax, cl
	and	eax, [mask.Red]
	mov	cl, [unshift.Red]
	shl	eax, cl
	stosb

	mov	eax, [esi]
	mov	cl, [shift.Alpha]
	shr	eax, cl
	and	eax, [mask.Alpha]
	mov	cl, [unshift.Alpha]
	shl	eax, cl
	stosb

	add	esi, [delta]

	pop	ecx
	dec	ecx
	jnz	.next_pixel

	pop	ecx
	dec	ecx
	jnz	.next_line

;;------------------------------------------------------------------------------------------------;;

  .exit:
	xor	eax, eax
	pop	edi
	ret

  .error:
	or	eax, -1
	pop	edi
	ret
	
.calc_shift:
	xor	eax, eax
	or	ecx, ecx
	jnz	@f
	retn
    @@: test	ecx, 1
	jnz	@f
   .zz: shr	ecx, 1
	inc	eax
	jmp	@b
    @@: test	ecx, 0100000000b
	jnz	.zz
	retn
.calc_unshift:
	xor	eax, eax
	or	ecx, ecx
	jnz	@f
	retn
    @@: test	ecx, 1
	jz	@f
	shr	ecx, 1
	inc	eax
	jmp	@b
    @@: sub	eax, 8
	neg	eax
	retn
endp

if 0
;;================================================================================================;;
proc img.decode.bmp._.jpeg ;//////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? --- TBD ---                                                                                    ;;
;;------------------------------------------------------------------------------------------------;;
;> ebx = raw image data                                                                           ;;
;> edx = image data                                                                               ;;
;;------------------------------------------------------------------------------------------------;;
;< --- TBD ---                                                                                    ;;
;;================================================================================================;;
	xor	eax, eax
	ret
endp

;;================================================================================================;;
proc img.decode.bmp._.png ;///////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? --- TBD ---                                                                                    ;;
;;------------------------------------------------------------------------------------------------;;
;> ebx = raw image data                                                                           ;;
;> edx = image data                                                                               ;;
;;------------------------------------------------------------------------------------------------;;
;< --- TBD ---                                                                                    ;;
;;================================================================================================;;
	xor	eax, eax
	ret
endp
end if

;;================================================================================================;;
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
;;================================================================================================;;
;! Below is private data you should never use directly from your code                             ;;
;;================================================================================================;;
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
;;================================================================================================;;


;