png: Move metadata.

This commit is contained in:
Jeroen van Rijn
2021-10-06 22:43:33 +02:00
parent 263d63aa56
commit c4b4a841d6
5 changed files with 218 additions and 222 deletions

View File

@@ -26,8 +26,11 @@ Image :: struct {
*/
background: Maybe([3]u16),
metadata_ptr: rawptr,
metadata_type: typeid,
metadata: Image_Metadata,
}
Image_Metadata :: union {
^PNG_Info,
}
/*
@@ -152,10 +155,101 @@ PNG_Error :: enum {
Invalid_Chunk_Length,
}
/*
PNG-specific structs
*/
PNG_Info :: struct {
header: PNG_IHDR,
chunks: [dynamic]PNG_Chunk,
}
PNG_Chunk_Header :: struct #packed {
length: u32be,
type: PNG_Chunk_Type,
}
PNG_Chunk :: struct #packed {
header: PNG_Chunk_Header,
data: []byte,
crc: u32be,
}
PNG_Chunk_Type :: enum u32be {
// IHDR must come first in a file
IHDR = 'I' << 24 | 'H' << 16 | 'D' << 8 | 'R',
// PLTE must precede the first IDAT chunk
PLTE = 'P' << 24 | 'L' << 16 | 'T' << 8 | 'E',
bKGD = 'b' << 24 | 'K' << 16 | 'G' << 8 | 'D',
tRNS = 't' << 24 | 'R' << 16 | 'N' << 8 | 'S',
IDAT = 'I' << 24 | 'D' << 16 | 'A' << 8 | 'T',
iTXt = 'i' << 24 | 'T' << 16 | 'X' << 8 | 't',
tEXt = 't' << 24 | 'E' << 16 | 'X' << 8 | 't',
zTXt = 'z' << 24 | 'T' << 16 | 'X' << 8 | 't',
iCCP = 'i' << 24 | 'C' << 16 | 'C' << 8 | 'P',
pHYs = 'p' << 24 | 'H' << 16 | 'Y' << 8 | 's',
gAMA = 'g' << 24 | 'A' << 16 | 'M' << 8 | 'A',
tIME = 't' << 24 | 'I' << 16 | 'M' << 8 | 'E',
sPLT = 's' << 24 | 'P' << 16 | 'L' << 8 | 'T',
sRGB = 's' << 24 | 'R' << 16 | 'G' << 8 | 'B',
hIST = 'h' << 24 | 'I' << 16 | 'S' << 8 | 'T',
cHRM = 'c' << 24 | 'H' << 16 | 'R' << 8 | 'M',
sBIT = 's' << 24 | 'B' << 16 | 'I' << 8 | 'T',
/*
eXIf tags are not part of the core spec, but have been ratified
in v1.5.0 of the PNG Ext register.
We will provide unprocessed chunks to the caller if `.return_metadata` is set.
Applications are free to implement an Exif decoder.
*/
eXIf = 'e' << 24 | 'X' << 16 | 'I' << 8 | 'f',
// PNG files must end with IEND
IEND = 'I' << 24 | 'E' << 16 | 'N' << 8 | 'D',
/*
XCode sometimes produces "PNG" files that don't adhere to the PNG spec.
We recognize them only in order to avoid doing further work on them.
Some tools like PNG Defry may be able to repair them, but we're not
going to reward Apple for producing proprietary broken files purporting
to be PNGs by supporting them.
*/
iDOT = 'i' << 24 | 'D' << 16 | 'O' << 8 | 'T',
CbGI = 'C' << 24 | 'b' << 16 | 'H' << 8 | 'I',
}
PNG_IHDR :: struct #packed {
width: u32be,
height: u32be,
bit_depth: u8,
color_type: PNG_Color_Type,
compression_method: u8,
filter_method: u8,
interlace_method: PNG_Interlace_Method,
}
PNG_IHDR_SIZE :: size_of(PNG_IHDR)
#assert (PNG_IHDR_SIZE == 13)
PNG_Color_Value :: enum u8 {
Paletted = 0, // 1 << 0 = 1
Color = 1, // 1 << 1 = 2
Alpha = 2, // 1 << 2 = 4
}
PNG_Color_Type :: distinct bit_set[PNG_Color_Value; u8]
PNG_Interlace_Method :: enum u8 {
None = 0,
Adam7 = 1,
}
/*
Functions to help with image buffer calculations
*/
compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) {
size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height
return
@@ -164,7 +258,6 @@ compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes
/*
For when you have an RGB(A) image, but want a particular channel.
*/
Channel :: enum u8 {
R = 1,
G = 2,
@@ -226,8 +319,8 @@ return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok
res.depth = img.depth
res.pixels = t
res.background = img.background
res.metadata_ptr = img.metadata_ptr
res.metadata_type = img.metadata_type
// res.metadata_ptr = img.metadata_ptr
// res.metadata_type = img.metadata_type
return res, true
}

View File

@@ -53,93 +53,91 @@ demo :: proc() {
} else {
fmt.printf("Image: %vx%vx%v, %v-bit.\n", img.width, img.height, img.channels, img.depth)
assert(img.metadata_ptr != nil && img.metadata_type == Info)
v := (^Info)(img.metadata_ptr)
// Handle ancillary chunks as you wish.
// We provide helper functions for a few types.
for c in v.chunks {
#partial switch c.header.type {
case .tIME:
if t, t_ok := core_time(c); t_ok {
fmt.printf("[tIME]: %v\n", t)
}
case .gAMA:
if gama, gama_ok := gamma(c); gama_ok {
fmt.printf("[gAMA]: %v\n", gama)
}
case .pHYs:
if phys, phys_ok := phys(c); phys_ok {
if phys.unit == .Meter {
xm := f32(img.width) / f32(phys.ppu_x)
ym := f32(img.height) / f32(phys.ppu_y)
dpi_x, dpi_y := phys_to_dpi(phys)
fmt.printf("[pHYs] Image resolution is %v x %v pixels per meter.\n", phys.ppu_x, phys.ppu_y)
fmt.printf("[pHYs] Image resolution is %v x %v DPI.\n", dpi_x, dpi_y)
fmt.printf("[pHYs] Image dimensions are %v x %v meters.\n", xm, ym)
} else {
fmt.printf("[pHYs] x: %v, y: %v pixels per unknown unit.\n", phys.ppu_x, phys.ppu_y)
if v, ok := img.metadata.(^image.PNG_Info); ok {
// Handle ancillary chunks as you wish.
// We provide helper functions for a few types.
for c in v.chunks {
#partial switch c.header.type {
case .tIME:
if t, t_ok := core_time(c); t_ok {
fmt.printf("[tIME]: %v\n", t)
}
}
case .iTXt, .zTXt, .tEXt:
res, ok_text := text(c)
if ok_text {
if c.header.type == .iTXt {
fmt.printf("[iTXt] %v (%v:%v): %v\n", res.keyword, res.language, res.keyword_localized, res.text)
} else {
fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text)
case .gAMA:
if gama, gama_ok := gamma(c); gama_ok {
fmt.printf("[gAMA]: %v\n", gama)
}
case .pHYs:
if phys, phys_ok := phys(c); phys_ok {
if phys.unit == .Meter {
xm := f32(img.width) / f32(phys.ppu_x)
ym := f32(img.height) / f32(phys.ppu_y)
dpi_x, dpi_y := phys_to_dpi(phys)
fmt.printf("[pHYs] Image resolution is %v x %v pixels per meter.\n", phys.ppu_x, phys.ppu_y)
fmt.printf("[pHYs] Image resolution is %v x %v DPI.\n", dpi_x, dpi_y)
fmt.printf("[pHYs] Image dimensions are %v x %v meters.\n", xm, ym)
} else {
fmt.printf("[pHYs] x: %v, y: %v pixels per unknown unit.\n", phys.ppu_x, phys.ppu_y)
}
}
case .iTXt, .zTXt, .tEXt:
res, ok_text := text(c)
if ok_text {
if c.header.type == .iTXt {
fmt.printf("[iTXt] %v (%v:%v): %v\n", res.keyword, res.language, res.keyword_localized, res.text)
} else {
fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text)
}
}
defer text_destroy(res)
case .bKGD:
fmt.printf("[bKGD] %v\n", img.background)
case .eXIf:
if res, ok_exif := exif(c); ok_exif {
/*
Other than checking the signature and byte order, we don't handle Exif data.
If you wish to interpret it, pass it to an Exif parser.
*/
fmt.printf("[eXIf] %v\n", res)
}
case .PLTE:
if plte, plte_ok := plte(c); plte_ok {
fmt.printf("[PLTE] %v\n", plte)
} else {
fmt.printf("[PLTE] Error\n")
}
case .hIST:
if res, ok_hist := hist(c); ok_hist {
fmt.printf("[hIST] %v\n", res)
}
case .cHRM:
if res, ok_chrm := chrm(c); ok_chrm {
fmt.printf("[cHRM] %v\n", res)
}
case .sPLT:
res, ok_splt := splt(c)
if ok_splt {
fmt.printf("[sPLT] %v\n", res)
}
splt_destroy(res)
case .sBIT:
if res, ok_sbit := sbit(c); ok_sbit {
fmt.printf("[sBIT] %v\n", res)
}
case .iCCP:
res, ok_iccp := iccp(c)
if ok_iccp {
fmt.printf("[iCCP] %v\n", res)
}
iccp_destroy(res)
case .sRGB:
if res, ok_srgb := srgb(c); ok_srgb {
fmt.printf("[sRGB] Rendering intent: %v\n", res)
}
case:
type := c.header.type
name := chunk_type_to_name(&type)
fmt.printf("[%v]: %v\n", name, c.data)
}
defer text_destroy(res)
case .bKGD:
fmt.printf("[bKGD] %v\n", img.background)
case .eXIf:
if res, ok_exif := exif(c); ok_exif {
/*
Other than checking the signature and byte order, we don't handle Exif data.
If you wish to interpret it, pass it to an Exif parser.
*/
fmt.printf("[eXIf] %v\n", res)
}
case .PLTE:
if plte, plte_ok := plte(c); plte_ok {
fmt.printf("[PLTE] %v\n", plte)
} else {
fmt.printf("[PLTE] Error\n")
}
case .hIST:
if res, ok_hist := hist(c); ok_hist {
fmt.printf("[hIST] %v\n", res)
}
case .cHRM:
if res, ok_chrm := chrm(c); ok_chrm {
fmt.printf("[cHRM] %v\n", res)
}
case .sPLT:
res, ok_splt := splt(c)
if ok_splt {
fmt.printf("[sPLT] %v\n", res)
}
splt_destroy(res)
case .sBIT:
if res, ok_sbit := sbit(c); ok_sbit {
fmt.printf("[sBIT] %v\n", res)
}
case .iCCP:
res, ok_iccp := iccp(c)
if ok_iccp {
fmt.printf("[iCCP] %v\n", res)
}
iccp_destroy(res)
case .sRGB:
if res, ok_srgb := srgb(c); ok_srgb {
fmt.printf("[sRGB] Rendering intent: %v\n", res)
}
case:
type := c.header.type
name := chunk_type_to_name(&type)
fmt.printf("[%v]: %v\n", name, c.data)
}
}
}

View File

@@ -34,16 +34,13 @@ destroy :: proc(img: ^Image) {
bytes.buffer_destroy(&img.pixels)
assert(img.metadata_ptr != nil && img.metadata_type == Info)
v := (^Info)(img.metadata_ptr)
for chunk in &v.chunks {
delete(chunk.data)
if v, ok := img.metadata.(^image.PNG_Info); ok {
for chunk in &v.chunks {
delete(chunk.data)
}
delete(v.chunks)
free(v)
}
delete(v.chunks)
// Clean up Info.
free(img.metadata_ptr)
free(img)
}
@@ -51,7 +48,7 @@ destroy :: proc(img: ^Image) {
Chunk helpers
*/
gamma :: proc(c: Chunk) -> (res: f32, ok: bool) {
gamma :: proc(c: image.PNG_Chunk) -> (res: f32, ok: bool) {
if c.header.type != .gAMA || len(c.data) != size_of(gAMA) {
return {}, false
}
@@ -61,7 +58,7 @@ gamma :: proc(c: Chunk) -> (res: f32, ok: bool) {
INCHES_PER_METER :: 1000.0 / 25.4
phys :: proc(c: Chunk) -> (res: pHYs, ok: bool) {
phys :: proc(c: image.PNG_Chunk) -> (res: pHYs, ok: bool) {
if c.header.type != .pHYs || len(c.data) != size_of(pHYs) {
return {}, false
}
@@ -73,7 +70,7 @@ phys_to_dpi :: proc(p: pHYs) -> (x_dpi, y_dpi: f32) {
return f32(p.ppu_x) / INCHES_PER_METER, f32(p.ppu_y) / INCHES_PER_METER
}
time :: proc(c: Chunk) -> (res: tIME, ok: bool) {
time :: proc(c: image.PNG_Chunk) -> (res: tIME, ok: bool) {
if c.header.type != .tIME || len(c.data) != size_of(tIME) {
return {}, false
}
@@ -81,7 +78,7 @@ time :: proc(c: Chunk) -> (res: tIME, ok: bool) {
return (^tIME)(raw_data(c.data))^, true
}
core_time :: proc(c: Chunk) -> (t: coretime.Time, ok: bool) {
core_time :: proc(c: image.PNG_Chunk) -> (t: coretime.Time, ok: bool) {
if png_time, png_ok := time(c); png_ok {
using png_time
return coretime.datetime_to_time(
@@ -93,7 +90,7 @@ core_time :: proc(c: Chunk) -> (t: coretime.Time, ok: bool) {
}
}
text :: proc(c: Chunk) -> (res: Text, ok: bool) {
text :: proc(c: image.PNG_Chunk) -> (res: Text, ok: bool) {
assert(len(c.data) == int(c.header.length))
#partial switch c.header.type {
case .tEXt:
@@ -196,7 +193,7 @@ text_destroy :: proc(text: Text) {
delete(text.text)
}
iccp :: proc(c: Chunk) -> (res: iCCP, ok: bool) {
iccp :: proc(c: image.PNG_Chunk) -> (res: iCCP, ok: bool) {
ok = true
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator)
@@ -232,7 +229,7 @@ iccp_destroy :: proc(i: iCCP) {
}
srgb :: proc(c: Chunk) -> (res: sRGB, ok: bool) {
srgb :: proc(c: image.PNG_Chunk) -> (res: sRGB, ok: bool) {
if c.header.type != .sRGB || len(c.data) != size_of(sRGB_Rendering_Intent) {
return {}, false
}
@@ -244,7 +241,7 @@ srgb :: proc(c: Chunk) -> (res: sRGB, ok: bool) {
return res, true
}
plte :: proc(c: Chunk) -> (res: PLTE, ok: bool) {
plte :: proc(c: image.PNG_Chunk) -> (res: PLTE, ok: bool) {
if c.header.type != .PLTE {
return {}, false
}
@@ -258,7 +255,7 @@ plte :: proc(c: Chunk) -> (res: PLTE, ok: bool) {
return
}
splt :: proc(c: Chunk) -> (res: sPLT, ok: bool) {
splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) {
if c.header.type != .sPLT {
return {}, false
}
@@ -309,7 +306,7 @@ splt_destroy :: proc(s: sPLT) {
delete(s.name)
}
sbit :: proc(c: Chunk) -> (res: [4]u8, ok: bool) {
sbit :: proc(c: image.PNG_Chunk) -> (res: [4]u8, ok: bool) {
/*
Returns [4]u8 with the significant bits in each channel.
A channel will contain zero if not applicable to the PNG color type.
@@ -327,7 +324,7 @@ sbit :: proc(c: Chunk) -> (res: [4]u8, ok: bool) {
}
hist :: proc(c: Chunk) -> (res: hIST, ok: bool) {
hist :: proc(c: image.PNG_Chunk) -> (res: hIST, ok: bool) {
if c.header.type != .hIST {
return {}, false
}
@@ -349,7 +346,7 @@ hist :: proc(c: Chunk) -> (res: hIST, ok: bool) {
return
}
chrm :: proc(c: Chunk) -> (res: cHRM, ok: bool) {
chrm :: proc(c: image.PNG_Chunk) -> (res: cHRM, ok: bool) {
ok = true
if c.header.length != size_of(cHRM_Raw) {
return {}, false
@@ -367,7 +364,7 @@ chrm :: proc(c: Chunk) -> (res: cHRM, ok: bool) {
return
}
exif :: proc(c: Chunk) -> (res: Exif, ok: bool) {
exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) {
ok = true

View File

@@ -51,95 +51,6 @@ Signature :: enum u64be {
PNG = 0x89 << 56 | 'P' << 48 | 'N' << 40 | 'G' << 32 | '\r' << 24 | '\n' << 16 | 0x1a << 8 | '\n',
}
Info :: struct {
header: IHDR,
chunks: [dynamic]Chunk,
}
Chunk_Header :: struct #packed {
length: u32be,
type: Chunk_Type,
}
Chunk :: struct #packed {
header: Chunk_Header,
data: []byte,
crc: u32be,
}
Chunk_Type :: enum u32be {
// IHDR must come first in a file
IHDR = 'I' << 24 | 'H' << 16 | 'D' << 8 | 'R',
// PLTE must precede the first IDAT chunk
PLTE = 'P' << 24 | 'L' << 16 | 'T' << 8 | 'E',
bKGD = 'b' << 24 | 'K' << 16 | 'G' << 8 | 'D',
tRNS = 't' << 24 | 'R' << 16 | 'N' << 8 | 'S',
IDAT = 'I' << 24 | 'D' << 16 | 'A' << 8 | 'T',
iTXt = 'i' << 24 | 'T' << 16 | 'X' << 8 | 't',
tEXt = 't' << 24 | 'E' << 16 | 'X' << 8 | 't',
zTXt = 'z' << 24 | 'T' << 16 | 'X' << 8 | 't',
iCCP = 'i' << 24 | 'C' << 16 | 'C' << 8 | 'P',
pHYs = 'p' << 24 | 'H' << 16 | 'Y' << 8 | 's',
gAMA = 'g' << 24 | 'A' << 16 | 'M' << 8 | 'A',
tIME = 't' << 24 | 'I' << 16 | 'M' << 8 | 'E',
sPLT = 's' << 24 | 'P' << 16 | 'L' << 8 | 'T',
sRGB = 's' << 24 | 'R' << 16 | 'G' << 8 | 'B',
hIST = 'h' << 24 | 'I' << 16 | 'S' << 8 | 'T',
cHRM = 'c' << 24 | 'H' << 16 | 'R' << 8 | 'M',
sBIT = 's' << 24 | 'B' << 16 | 'I' << 8 | 'T',
/*
eXIf tags are not part of the core spec, but have been ratified
in v1.5.0 of the PNG Ext register.
We will provide unprocessed chunks to the caller if `.return_metadata` is set.
Applications are free to implement an Exif decoder.
*/
eXIf = 'e' << 24 | 'X' << 16 | 'I' << 8 | 'f',
// PNG files must end with IEND
IEND = 'I' << 24 | 'E' << 16 | 'N' << 8 | 'D',
/*
XCode sometimes produces "PNG" files that don't adhere to the PNG spec.
We recognize them only in order to avoid doing further work on them.
Some tools like PNG Defry may be able to repair them, but we're not
going to reward Apple for producing proprietary broken files purporting
to be PNGs by supporting them.
*/
iDOT = 'i' << 24 | 'D' << 16 | 'O' << 8 | 'T',
CbGI = 'C' << 24 | 'b' << 16 | 'H' << 8 | 'I',
}
IHDR :: struct #packed {
width: u32be,
height: u32be,
bit_depth: u8,
color_type: Color_Type,
compression_method: u8,
filter_method: u8,
interlace_method: Interlace_Method,
}
IHDR_SIZE :: size_of(IHDR)
#assert (IHDR_SIZE == 13)
Color_Value :: enum u8 {
Paletted = 0, // 1 << 0 = 1
Color = 1, // 1 << 1 = 2
Alpha = 2, // 1 << 2 = 4
}
Color_Type :: distinct bit_set[Color_Value; u8]
Interlace_Method :: enum u8 {
None = 0,
Adam7 = 1,
}
Row_Filter :: enum u8 {
None = 0,
Sub = 1,
@@ -262,8 +173,8 @@ ADAM7_Y_SPACING := []int{ 8,8,8,4,4,2,2 }
// Implementation starts here
read_chunk :: proc(ctx: ^$C) -> (chunk: Chunk, err: Error) {
ch, e := compress.read_data(ctx, Chunk_Header)
read_chunk :: proc(ctx: ^$C) -> (chunk: image.PNG_Chunk, err: Error) {
ch, e := compress.read_data(ctx, image.PNG_Chunk_Header)
if e != .None {
return {}, compress.General_Error.Stream_Too_Short
}
@@ -305,7 +216,7 @@ read_chunk :: proc(ctx: ^$C) -> (chunk: Chunk, err: Error) {
return chunk, nil
}
copy_chunk :: proc(src: Chunk, allocator := context.allocator) -> (dest: Chunk, err: Error) {
copy_chunk :: proc(src: image.PNG_Chunk, allocator := context.allocator) -> (dest: image.PNG_Chunk, err: Error) {
if int(src.header.length) != len(src.data) {
return {}, .Invalid_Chunk_Length
}
@@ -318,7 +229,7 @@ copy_chunk :: proc(src: Chunk, allocator := context.allocator) -> (dest: Chunk,
return
}
append_chunk :: proc(list: ^[dynamic]Chunk, src: Chunk, allocator := context.allocator) -> (err: Error) {
append_chunk :: proc(list: ^[dynamic]image.PNG_Chunk, src: image.PNG_Chunk, allocator := context.allocator) -> (err: Error) {
if int(src.header.length) != len(src.data) {
return .Invalid_Chunk_Length
}
@@ -334,13 +245,13 @@ append_chunk :: proc(list: ^[dynamic]Chunk, src: Chunk, allocator := context.all
return
}
read_header :: proc(ctx: ^$C) -> (IHDR, Error) {
read_header :: proc(ctx: ^$C) -> (image.PNG_IHDR, Error) {
c, e := read_chunk(ctx)
if e != nil {
return {}, e
}
header := (^IHDR)(raw_data(c.data))^
header := (^image.PNG_IHDR)(raw_data(c.data))^
// Validate IHDR
using header
if width == 0 || height == 0 || u128(width) * u128(height) > MAX_DIMENSIONS {
@@ -407,7 +318,7 @@ read_header :: proc(ctx: ^$C) -> (IHDR, Error) {
return header, nil
}
chunk_type_to_name :: proc(type: ^Chunk_Type) -> string {
chunk_type_to_name :: proc(type: ^image.PNG_Chunk_Type) -> string {
t := transmute(^u8)type
return strings.string_from_ptr(t, 4)
}
@@ -462,9 +373,8 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
img = new(Image)
}
info := new(Info)
img.metadata_ptr = info
img.metadata_type = typeid_of(Info)
info := new(image.PNG_Info)
img.metadata = info
signature, io_error := compress.read_data(ctx, Signature)
if io_error != .None || signature != .PNG {
@@ -477,11 +387,11 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
idat_length := u64(0)
c: Chunk
ch: Chunk_Header
c: image.PNG_Chunk
ch: image.PNG_Chunk_Header
e: io.Error
header: IHDR
header: image.PNG_IHDR
// State to ensure correct chunk ordering.
seen_ihdr := false; first := true
@@ -492,7 +402,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
seen_iend := false
_plte := PLTE{}
trns := Chunk{}
trns := image.PNG_Chunk{}
final_image_channels := 0
@@ -502,7 +412,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
// Peek at next chunk's length and type.
// TODO: Some streams may not provide seek/read_at
ch, e = compress.peek_data(ctx, Chunk_Header)
ch, e = compress.peek_data(ctx, image.PNG_Chunk_Header)
if e != .None {
return img, compress.General_Error.Stream_Too_Short
}
@@ -547,7 +457,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
img.height = int(header.height)
using header
h := IHDR{
h := image.PNG_IHDR{
width = width,
height = height,
bit_depth = bit_depth,
@@ -607,7 +517,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
return {}, image.PNG_Error.IDAT_Size_Too_Large
}
ch, e = compress.peek_data(ctx, Chunk_Header)
ch, e = compress.peek_data(ctx, image.PNG_Chunk_Header)
if e != .None {
return img, compress.General_Error.Stream_Too_Short
}
@@ -1599,7 +1509,7 @@ defilter_16 :: proc(params: ^Filter_Params) -> (ok: bool) {
return
}
defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^IHDR, options: Options) -> (err: Error) {
defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IHDR, options: Options) -> (err: Error) {
input := bytes.buffer_to_bytes(filter_bytes)
width := int(header.width)
height := int(header.height)

View File

@@ -1504,10 +1504,8 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) {
passed &= test.hash == hash
if .return_metadata in test.options {
v: ^png.Info
if img.metadata_ptr != nil && img.metadata_type == png.Info {
v = (^png.Info)(img.metadata_ptr)
if v, ok := img.metadata.(^image.PNG_Info); ok {
for c in v.chunks {
#partial switch(c.header.type) {
case .gAMA: