transparency chunk
This commit is contained in:
parent
c0803c3336
commit
5f7908f8a4
|
@ -7,7 +7,7 @@ const
|
||||||
|
|
||||||
type
|
type
|
||||||
ChunkCounts = object
|
ChunkCounts = object
|
||||||
PLTE, IDAT: uint8
|
PLTE, IDAT, tRNS: uint8
|
||||||
|
|
||||||
PngHeader = object
|
PngHeader = object
|
||||||
width, height: int
|
width, height: int
|
||||||
|
@ -146,7 +146,9 @@ proc unfilter(
|
||||||
result[unfiteredIdx(x, y)] = value
|
result[unfiteredIdx(x, y)] = value
|
||||||
|
|
||||||
proc parseImageData(
|
proc parseImageData(
|
||||||
header: PngHeader, palette: seq[array[3, uint8]], data: seq[uint8]
|
header: PngHeader,
|
||||||
|
palette: seq[array[3, uint8]],
|
||||||
|
transparency, data: seq[uint8]
|
||||||
): seq[ColorRGBA] =
|
): seq[ColorRGBA] =
|
||||||
result.setLen(header.width * header.height)
|
result.setLen(header.width * header.height)
|
||||||
|
|
||||||
|
@ -178,6 +180,7 @@ proc parseImageData(
|
||||||
|
|
||||||
case header.colorType:
|
case header.colorType:
|
||||||
of 0:
|
of 0:
|
||||||
|
let special = if transparency.len == 2: transparency[1].int else: -1
|
||||||
var bytePos, bitPos: int
|
var bytePos, bitPos: int
|
||||||
for y in 0 ..< header.height:
|
for y in 0 ..< header.height:
|
||||||
for x in 0 ..< header.width:
|
for x in 0 ..< header.width:
|
||||||
|
@ -204,8 +207,9 @@ proc parseImageData(
|
||||||
inc bytePos
|
inc bytePos
|
||||||
bitPos = 0
|
bitPos = 0
|
||||||
|
|
||||||
|
let alpha = if value.int == special: 0 else: 255
|
||||||
result[x + y * header.width] = ColorRGBA(
|
result[x + y * header.width] = ColorRGBA(
|
||||||
r: value, g: value, b: value, a: 255
|
r: value, g: value, b: value, a: alpha.uint8
|
||||||
)
|
)
|
||||||
|
|
||||||
# If we move to a new row, skip to the next full byte
|
# If we move to a new row, skip to the next full byte
|
||||||
|
@ -213,13 +217,21 @@ proc parseImageData(
|
||||||
inc bytePos
|
inc bytePos
|
||||||
bitPos = 0
|
bitPos = 0
|
||||||
of 2:
|
of 2:
|
||||||
|
let special =
|
||||||
|
if transparency.len == 6:
|
||||||
|
ColorRGBA(
|
||||||
|
r: transparency[1], g: transparency[3], b: transparency[5], a: 255
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
ColorRGBA()
|
||||||
var bytePos: int
|
var bytePos: int
|
||||||
for y in 0 ..< header.height:
|
for y in 0 ..< header.height:
|
||||||
for x in 0 ..< header.width:
|
for x in 0 ..< header.width:
|
||||||
let rgb = cast[ptr array[3, uint8]](unfiltered[bytePos].unsafeAddr)[]
|
let rgb = cast[ptr array[3, uint8]](unfiltered[bytePos].unsafeAddr)[]
|
||||||
result[x + y * header.width] = ColorRGBA(
|
var rgba = ColorRGBA(r: rgb[0], g: rgb[1], b: rgb[2], a: 255)
|
||||||
r: rgb[0], g: rgb[1], b: rgb[2], a: 255
|
if rgba == special:
|
||||||
)
|
rgba.a = 0
|
||||||
|
result[x + y * header.width] = rgba
|
||||||
bytePos += 3
|
bytePos += 3
|
||||||
of 3:
|
of 3:
|
||||||
var bytePos, bitPos: int
|
var bytePos, bitPos: int
|
||||||
|
@ -247,9 +259,15 @@ proc parseImageData(
|
||||||
if value.int >= palette.len:
|
if value.int >= palette.len:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
let rgb = palette[value]
|
let
|
||||||
|
rgb = palette[value]
|
||||||
|
transparency =
|
||||||
|
if transparency.len > value.int:
|
||||||
|
transparency[value]
|
||||||
|
else:
|
||||||
|
255
|
||||||
result[x + y * header.width] = ColorRGBA(
|
result[x + y * header.width] = ColorRGBA(
|
||||||
r: rgb[0], g: rgb[1], b: rgb[2], a: 255
|
r: rgb[0], g: rgb[1], b: rgb[2], a: transparency
|
||||||
)
|
)
|
||||||
|
|
||||||
# If we move to a new row, skip to the next full byte
|
# If we move to a new row, skip to the next full byte
|
||||||
|
@ -297,7 +315,7 @@ proc decodePng*(data: seq[uint8]): Image =
|
||||||
counts = ChunkCounts()
|
counts = ChunkCounts()
|
||||||
header: PngHeader
|
header: PngHeader
|
||||||
palette: seq[array[3, uint8]]
|
palette: seq[array[3, uint8]]
|
||||||
imageData: seq[uint8]
|
transparency, imageData: seq[uint8]
|
||||||
prevChunkType: string
|
prevChunkType: string
|
||||||
|
|
||||||
# First chunk must be IHDR
|
# First chunk must be IHDR
|
||||||
|
@ -333,9 +351,26 @@ proc decodePng*(data: seq[uint8]): Image =
|
||||||
failInvalid()
|
failInvalid()
|
||||||
of "PLTE":
|
of "PLTE":
|
||||||
inc counts.PLTE
|
inc counts.PLTE
|
||||||
if counts.PLTE > 1 or counts.IDAT > 0:
|
if counts.PLTE > 1 or counts.IDAT > 0 or counts.tRNS > 0:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
palette = parsePalette(data[pos ..< pos + chunkLen])
|
palette = parsePalette(data[pos ..< pos + chunkLen])
|
||||||
|
of "tRNS":
|
||||||
|
inc counts.tRNS
|
||||||
|
if counts.tRNS > 1 or counts.IDAT > 0:
|
||||||
|
failInvalid()
|
||||||
|
transparency = data[pos ..< pos + chunkLen]
|
||||||
|
case header.colorType:
|
||||||
|
of 0:
|
||||||
|
if transparency.len != 2:
|
||||||
|
failInvalid()
|
||||||
|
of 2:
|
||||||
|
if transparency.len != 6:
|
||||||
|
failInvalid()
|
||||||
|
of 3:
|
||||||
|
if transparency.len > palette.len:
|
||||||
|
failInvalid()
|
||||||
|
else:
|
||||||
|
failInvalid()
|
||||||
of "IDAT":
|
of "IDAT":
|
||||||
inc counts.IDAT
|
inc counts.IDAT
|
||||||
if counts.IDAT > 1 and prevChunkType != "IDAT":
|
if counts.IDAT > 1 and prevChunkType != "IDAT":
|
||||||
|
@ -372,7 +407,7 @@ proc decodePng*(data: seq[uint8]): Image =
|
||||||
result = Image()
|
result = Image()
|
||||||
result.width = header.width
|
result.width = header.width
|
||||||
result.height = header.height
|
result.height = header.height
|
||||||
result.data = parseImageData(header, palette, imageData)
|
result.data = parseImageData(header, palette, transparency, imageData)
|
||||||
|
|
||||||
proc decodePng*(data: string): Image {.inline.} =
|
proc decodePng*(data: string): Image {.inline.} =
|
||||||
decodePng(cast[seq[uint8]](data))
|
decodePng(cast[seq[uint8]](data))
|
||||||
|
|
|
@ -73,6 +73,109 @@ const
|
||||||
"s39n3p04", # 39x39 paletted file, no interlacing
|
"s39n3p04", # 39x39 paletted file, no interlacing
|
||||||
# "s40i3p04", # 40x40 paletted file, interlaced
|
# "s40i3p04", # 40x40 paletted file, interlaced
|
||||||
"s40n3p04", # 40x40 paletted file, no interlacing
|
"s40n3p04", # 40x40 paletted file, no interlacing
|
||||||
|
|
||||||
|
# "bgai4a08", # 8 bit grayscale, alpha, no background chunk, interlaced
|
||||||
|
# "bgai4a16", # 16 bit grayscale, alpha, no background chunk, interlaced
|
||||||
|
"bgan6a08", # 3x8 bits rgb color, alpha, no background chunk
|
||||||
|
# "bgan6a16", # 3x16 bits rgb color, alpha, no background chunk
|
||||||
|
"bgbn4a08", # 8 bit grayscale, alpha, black background chunk
|
||||||
|
# "bggn4a16", # 16 bit grayscale, alpha, gray background chunk
|
||||||
|
"bgwn6a08", # 3x8 bits rgb color, alpha, white background chunk
|
||||||
|
# "bgyn6a16", # 3x16 bits rgb color, alpha, yellow background chunk
|
||||||
|
|
||||||
|
# "tbbn0g04", # transparent, black background chunk
|
||||||
|
# # "tbbn2c16", # transparent, blue background chunk
|
||||||
|
"tbbn3p08", # transparent, black background chunk
|
||||||
|
# # "tbgn2c16", # transparent, green background chunk
|
||||||
|
"tbgn3p08", # transparent, light-gray background chunk
|
||||||
|
"tbrn2c08", # transparent, red background chunk
|
||||||
|
# # "tbwn0g16", # transparent, white background chunk
|
||||||
|
"tbwn3p08", # transparent, white background chunk
|
||||||
|
"tbyn3p08", # transparent, yellow background chunk
|
||||||
|
"tp0n0g08", # not transparent for reference (logo on gray)
|
||||||
|
"tp0n2c08", # not transparent for reference (logo on gray)
|
||||||
|
"tp0n3p08", # not transparent for reference (logo on gray)
|
||||||
|
"tp1n3p08", # transparent, but no background chunk
|
||||||
|
"tm3n3p02", # multiple levels of transparency, 3 entries
|
||||||
|
|
||||||
|
# "g03n0g16", # grayscale, file-gamma = 0.35
|
||||||
|
"g03n2c08", # color, file-gamma = 0.35
|
||||||
|
"g03n3p04", # paletted, file-gamma = 0.35
|
||||||
|
# "g04n0g16", # grayscale, file-gamma = 0.45
|
||||||
|
"g04n2c08", # color, file-gamma = 0.45
|
||||||
|
"g04n3p04", # paletted, file-gamma = 0.45
|
||||||
|
# "g05n0g16", # grayscale, file-gamma = 0.55
|
||||||
|
"g05n2c08", # color, file-gamma = 0.55
|
||||||
|
"g05n3p04", # paletted, file-gamma = 0.55
|
||||||
|
# "g07n0g16", # grayscale, file-gamma = 0.70
|
||||||
|
"g07n2c08", # color, file-gamma = 0.70
|
||||||
|
"g07n3p04", # paletted, file-gamma = 0.70
|
||||||
|
# "g10n0g16", # grayscale, file-gamma = 1.00
|
||||||
|
"g10n2c08", # color, file-gamma = 1.00
|
||||||
|
"g10n3p04", # paletted, file-gamma = 1.00
|
||||||
|
# "g25n0g16", # grayscale, file-gamma = 2.50
|
||||||
|
"g25n2c08", # color, file-gamma = 2.50
|
||||||
|
"g25n3p04", # paletted, file-gamma = 2.50
|
||||||
|
|
||||||
|
"f00n0g08", # grayscale, no interlacing, filter-type 0
|
||||||
|
"f00n2c08", # color, no interlacing, filter-type 0
|
||||||
|
"f01n0g08", # grayscale, no interlacing, filter-type 1
|
||||||
|
"f01n2c08", # color, no interlacing, filter-type 1
|
||||||
|
"f02n0g08", # grayscale, no interlacing, filter-type 2
|
||||||
|
"f02n2c08", # color, no interlacing, filter-type 2
|
||||||
|
"f03n0g08", # grayscale, no interlacing, filter-type 3
|
||||||
|
"f03n2c08", # color, no interlacing, filter-type 3
|
||||||
|
"f04n0g08", # grayscale, no interlacing, filter-type 4
|
||||||
|
"f04n2c08", # color, no interlacing, filter-type 4
|
||||||
|
"f99n0g04", # bit-depth 4, filter changing per scanline
|
||||||
|
|
||||||
|
# "pp0n2c16", # six-cube palette-chunk in true-color image
|
||||||
|
"pp0n6a08", # six-cube palette-chunk in true-color+alpha image
|
||||||
|
"ps1n0g08", # six-cube suggested palette (1 byte) in grayscale image
|
||||||
|
# "ps1n2c16", # six-cube suggested palette (1 byte) in true-color image
|
||||||
|
"ps2n0g08", # six-cube suggested palette (2 bytes) in grayscale image
|
||||||
|
# "ps2n2c16", # six-cube suggested palette (2 bytes) in true-color image
|
||||||
|
|
||||||
|
"ccwn2c08", # chroma chunk w:0.3127,0.3290 r:0.64,0.33 g:0.30,0.60 b:0.15,0.06
|
||||||
|
"ccwn3p08", # chroma chunk w:0.3127,0.3290 r:0.64,0.33 g:0.30,0.60 b:0.15,0.06
|
||||||
|
"cdfn2c08", # physical pixel dimensions, 8x32 flat pixels
|
||||||
|
"cdhn2c08", # physical pixel dimensions, 32x8 high pixels
|
||||||
|
"cdsn2c08", # physical pixel dimensions, 8x8 square pixels
|
||||||
|
"cdun2c08", # physical pixel dimensions, 1000 pixels per 1 meter
|
||||||
|
"ch1n3p04", # histogram 15 colors
|
||||||
|
"ch2n3p08", # histogram 256 colors
|
||||||
|
"cm0n0g04", # modification time, 01-jan-2000 12:34:56
|
||||||
|
"cm7n0g04", # modification time, 01-jan-1970 00:00:00
|
||||||
|
"cm9n0g04", # modification time, 31-dec-1999 23:59:59
|
||||||
|
# "cs3n2c16", # color, 13 significant bits
|
||||||
|
"cs3n3p08", # paletted, 3 significant bits
|
||||||
|
"cs5n2c08", # color, 5 significant bits
|
||||||
|
"cs5n3p08", # paletted, 5 significant bits
|
||||||
|
"cs8n2c08", # color, 8 significant bits (reference)
|
||||||
|
"cs8n3p08", # paletted, 8 significant bits (reference)
|
||||||
|
"ct0n0g04", # no textual data
|
||||||
|
"ct1n0g04", # with textual data
|
||||||
|
"ctzn0g04", # with compressed textual data
|
||||||
|
"cten0g04", # international UTF-8, english
|
||||||
|
"ctfn0g04", # international UTF-8, finnish
|
||||||
|
"ctgn0g04", # international UTF-8, greek
|
||||||
|
"cthn0g04", # international UTF-8, hindi
|
||||||
|
"ctjn0g04", # international UTF-8, japanese
|
||||||
|
"exif2c08", # chunk with jpeg exif data
|
||||||
|
|
||||||
|
# "oi1n0g16", # grayscale mother image with 1 idat-chunk
|
||||||
|
# "oi1n2c16", # color mother image with 1 idat-chunk
|
||||||
|
# "oi2n0g16", # grayscale image with 2 idat-chunks
|
||||||
|
# "oi2n2c16", # color image with 2 idat-chunks
|
||||||
|
# "oi4n0g16", # grayscale image with 4 unequal sized idat-chunks
|
||||||
|
# "oi4n2c16", # color image with 4 unequal sized idat-chunks
|
||||||
|
# "oi9n0g16", # grayscale image with all idat-chunks length one
|
||||||
|
# "oi9n2c16", # color image with all idat-chunks length one
|
||||||
|
|
||||||
|
"z00n2c08", # color, no interlacing, compression level 0 (none)
|
||||||
|
"z03n2c08", # color, no interlacing, compression level 3
|
||||||
|
"z06n2c08", # color, no interlacing, compression level 6 (default)
|
||||||
|
"z09n2c08", # color, no interlacing, compression level 9 (maximum)
|
||||||
]
|
]
|
||||||
|
|
||||||
pngSuiteCorruptedFiles* = [
|
pngSuiteCorruptedFiles* = [
|
||||||
|
|
Loading…
Reference in a new issue