libimg: Improve support of transparent PNG images.

* Support grayscale images with alpha channel.
* Support rgb images with transparent color.
* Process 'tRNS' chunk (simple transparency).

Transparent png images were already supported for color type 6, which
is RGBA. Now indexed images (color type 3) can also have transparency
via 'tRNS' chunk data.

git-svn-id: svn://kolibrios.org@8449 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Ivan Baravy 2020-12-18 22:08:51 +00:00
parent 045e0dbdd2
commit 459cb3ec5b
2 changed files with 130 additions and 38 deletions

View File

@ -633,6 +633,22 @@ proc img._.convert.bpp8a_to_bpp24 _src, _dst
endp
proc img._.convert.bpp8a_to_bpp32 _src, _dst
mov ecx, [ebx + Image.Width]
imul ecx, [ebx + Image.Height]
@@:
lodsw
shl eax, 8
mov al, ah
shl eax, 8
mov al, ah
stosd
dec ecx
jnz @b
ret
endp
img.convert.bpp8i.table:
dd Image.bpp24, img._.convert.bpp8i_to_bpp24
dd Image.bpp32, img._.convert.bpp8i_to_bpp32
@ -665,6 +681,7 @@ img.convert.bpp4i.table:
dd 0
img.convert.bpp8a.table:
dd Image.bpp24, img._.convert.bpp8a_to_bpp24
dd Image.bpp32, img._.convert.bpp8a_to_bpp32
dd 0
img.convert.table:

View File

@ -56,12 +56,13 @@ img.decode.png:
xor eax, eax ; .image = 0
pushad
mov ebp, esp
.localsize = 29*4
.localsize = 30*4
virtual at ebp - .localsize
.width dd ?
.height dd ?
.bit_depth dd ?
.color_type dd ?
.transparent_color dd ?
.bytes_per_pixel dd ?
.scanline_len dd ?
.bits_per_pixel dd ?
@ -158,6 +159,8 @@ end virtual
jz .iend
cmp eax, 'PLTE'
jz .palette
cmp eax, 'tRNS'
jz .transparency
; unrecognized chunk, ignore
lea esi, [esi+ecx+4]
pop ecx
@ -233,14 +236,17 @@ end virtual
add eax, 7
shr eax, 3
mov [.bytes_per_pixel], eax
mov [.transparent_color], 0
; allocate image
push Image.bpp24
pop eax
movi eax, Image.bpp32
cmp [.color_type], 2
jz @f
mov al, Image.bpp32
cmp [.color_type], 6
jz @f
mov al, Image.bpp8a
cmp [.color_type], 4
jz @f
mov al, Image.bpp8i
@@:
stdcall img.create, [.width], [.height], eax
@ -288,11 +294,73 @@ end virtual
lodsd
dec esi
bswap eax
shr eax, 8
mov al, 0xff
ror eax, 8
stosd
jmp .next_chunk
; convert 16 bit sample to 8 bit sample
macro convert_16_to_8
{
local .l1,.l2
xor ah, 0x80
js .l1
cmp al, ah
adc al, 0
jmp .l2
.l1:
cmp ah, al
sbb al, 0
.l2:
}
; tRNS chunk
.transparency:
mov eax, [.image]
test eax, eax
jz .invalid_chunk
cmp [.color_type], 2 ; rgb
jz .transparency_rgb
cmp [.color_type], 3 ; indexed
jz .transparency_indexed
add esi, ecx
jmp .next_chunk
.transparency_rgb:
cmp [.bit_depth], 16
jz .transparency_rgb16
lodsw
shl eax, 8
lodsw
shl eax, 8
lodsw
mov al, 0xff
ror eax, 8
mov [.transparent_color], eax
jmp .next_chunk
.transparency_rgb16:
lodsw
convert_16_to_8
shl ax, 8
shl eax, 8
lodsw
convert_16_to_8
shl ax, 8
shl eax, 8
lodsw
convert_16_to_8
shl ax, 8
mov al, 0xff
ror eax, 8
mov [.transparent_color], eax
jmp .next_chunk
.transparency_indexed:
mov edi, [eax + Image.Palette]
@@:
add edi, 3
movsb
loop @b
jmp .next_chunk
.idat:
jecxz .next_chunk
test ecx, ecx
jz .next_chunk
cmp [.idat_read], 0
jnz @f
lodsb
@ -654,22 +722,6 @@ macro init_block
init_block
lea eax, [edi+eax*4]
push eax
; convert 16 bit sample to 8 bit sample
macro convert_16_to_8
{
local .l1,.l2
xor ah, 0x80
js .l1
cmp al, ah
adc al, 0
jmp .l2
.l1:
cmp ah, al
sbb al, 0
.l2:
}
.rgb_alpha2_16bit.innloop1:
push edi
mov ecx, ebx
@ -872,20 +924,21 @@ local .l1
mov [.i], ecx
.rgb2.extloop:
init_block
lea eax, [eax*3]
add eax, edi
lea eax, [edi+eax*4]
push eax
.rgb2.innloop1:
push edi
mov ecx, ebx
.rgb2.innloop2:
mov al, [esi+2]
mov [edi], al
mov al, [esi+1]
mov [edi+1], al
mov al, [esi]
mov [edi+2], al
add edi, 3
mov eax, [esi]
bswap eax
mov al, 0xff
ror eax, 8
cmp eax, [.transparent_color]
jnz @f
and eax, 0x00ffffff
@@:
stosd
dec ecx
jnz .rgb2.innloop2
pop edi
@ -947,7 +1000,6 @@ local .l1
ja .rgb2_16bit
jmp .convert_done
.grayscale_alpha2:
call .create_grayscale_palette
cmp [.bit_depth], 16
jz .grayscale_alpha2_16bit
.grayscale_alpha2.next:
@ -961,11 +1013,29 @@ local .l1
mov [.i], ecx
.grayscale_alpha2.extloop:
init_block
add eax, eax
add eax, edi
push eax
mov al, [esi]
add esi, 2
block_byte_innerloop .grayscale_alpha2.extloop
lodsw
macro block_word_innerloop extloop
{
local .l1
.l1:
mov ecx, ebx
rep stosw
sub edi, ebx
add edi, [.row_distance]
dec edx
jnz .l1
pop edi ebx
mov eax, [.col_increment]
sub [.i], eax
ja extloop
add edi, [.col_distance]
mov eax, [.row_increment]
sub [.j], eax
}
block_word_innerloop .grayscale_alpha2.extloop
ja .grayscale_alpha2.next
jmp .convert_done
.grayscale_alpha2_16bit:
@ -979,12 +1049,17 @@ local .l1
mov [.i], ecx
.grayscale_alpha2_16bit.extloop:
init_block
add eax, eax
add eax, edi
push eax
mov ax, [esi]
add esi, 4
lodsw
convert_16_to_8
block_byte_innerloop .grayscale_alpha2_16bit.extloop
mov ecx, eax
lodsw
convert_16_to_8
mov ah, cl
xchg al, ah
block_word_innerloop .grayscale_alpha2_16bit.extloop
ja .grayscale_alpha2_16bit
.convert_done:
; next interlace pass
@ -1070,7 +1145,7 @@ local .l1
jz .graypal_common
mov edx, 0xFFFFFF
.graypal_common:
xor eax, eax
mov eax, 0xff000000
@@:
stosd
add eax, edx