[pbm] Normalize some errors, correct .depth

This commit is contained in:
Jeroen van Rijn
2022-04-30 14:34:07 +02:00
parent ae3deea153
commit d6a8216ce4
6 changed files with 70 additions and 77 deletions
+25 -16
View File
@@ -45,7 +45,7 @@ Image :: struct {
width: int, width: int,
height: int, height: int,
channels: int, channels: int,
depth: int, depth: int, // Channel depth in bits, typically 8 or 16
pixels: bytes.Buffer, pixels: bytes.Buffer,
/* /*
Some image loaders/writers can return/take an optional background color. Some image loaders/writers can return/take an optional background color.
@@ -141,13 +141,14 @@ Option :: enum {
alpha_drop_if_present, // Unimplemented for QOI. Returns error. alpha_drop_if_present, // Unimplemented for QOI. Returns error.
alpha_premultiply, // Unimplemented for QOI. Returns error. alpha_premultiply, // Unimplemented for QOI. Returns error.
blend_background, // Ignored for non-PNG formats blend_background, // Ignored for non-PNG formats
// Unimplemented // Unimplemented
do_not_expand_grayscale, do_not_expand_grayscale,
do_not_expand_indexed, do_not_expand_indexed,
do_not_expand_channels, do_not_expand_channels,
// SAVE OPTIONS // SAVE OPTIONS
qoi_all_channels_linear, // QOI, informative info. If not set, defaults to sRGB with linear alpha. qoi_all_channels_linear, // QOI, informative only. If not set, defaults to sRGB with linear alpha.
} }
Options :: distinct bit_set[Option] Options :: distinct bit_set[Option]
@@ -166,12 +167,29 @@ Error :: union #shared_nil {
General_Image_Error :: enum { General_Image_Error :: enum {
None = 0, None = 0,
// File I/O
Unable_To_Read_File,
Unable_To_Write_File,
// Invalid
Invalid_Signature,
Invalid_Input_Image,
Image_Dimensions_Too_Large,
Invalid_Image_Dimensions, Invalid_Image_Dimensions,
Invalid_Number_Of_Channels, Invalid_Number_Of_Channels,
Image_Dimensions_Too_Large,
Image_Does_Not_Adhere_to_Spec, Image_Does_Not_Adhere_to_Spec,
Invalid_Input_Image, Invalid_Image_Depth,
Invalid_Bit_Depth,
Invalid_Color_Space,
// More data than pixels to decode into, for example.
Corrupt,
// Output buffer is the wrong size
Invalid_Output, Invalid_Output,
// Allocation
Unable_To_Allocate_Or_Resize,
} }
/* /*
@@ -201,8 +219,6 @@ Netpbm_Error :: enum {
None = 0, None = 0,
// reading // reading
File_Not_Readable,
Invalid_Signature,
Invalid_Header_Token_Character, Invalid_Header_Token_Character,
Incomplete_Header, Incomplete_Header,
Invalid_Header_Value, Invalid_Header_Value,
@@ -212,9 +228,7 @@ Netpbm_Error :: enum {
Invalid_Buffer_Value, Invalid_Buffer_Value,
// writing // writing
File_Not_Writable,
Invalid_Format, Invalid_Format,
Invalid_Image_Depth,
} }
/* /*
@@ -222,7 +236,6 @@ Netpbm_Error :: enum {
*/ */
PNG_Error :: enum { PNG_Error :: enum {
None = 0, None = 0,
Invalid_PNG_Signature,
IHDR_Not_First_Chunk, IHDR_Not_First_Chunk,
IHDR_Corrupt, IHDR_Corrupt,
IDAT_Missing, IDAT_Missing,
@@ -338,14 +351,10 @@ PNG_Interlace_Method :: enum u8 {
*/ */
QOI_Error :: enum { QOI_Error :: enum {
None = 0, None = 0,
Invalid_QOI_Signature,
Invalid_Bit_Depth, // QOI supports only 8-bit images, error only returned from writer.
Invalid_Color_Space, // QOI allows 0 = sRGB or 1 = linear.
Corrupt, // More data than pixels to decode into, for example.
Missing_Or_Corrupt_Trailer, // Image seemed to have decoded okay, but trailer is missing or corrupt. Missing_Or_Corrupt_Trailer, // Image seemed to have decoded okay, but trailer is missing or corrupt.
} }
QOI_Magic :: u32be(0x716f6966) // "qoif" QOI_Magic :: u32be(0x716f6966) // "qoif"
QOI_Color_Space :: enum u8 { QOI_Color_Space :: enum u8 {
sRGB = 0, sRGB = 0,
@@ -1170,10 +1179,10 @@ write_bytes :: proc(buf: ^bytes.Buffer, data: []u8) -> (err: compress.General_Er
return nil return nil
} else if len(data) == 1 { } else if len(data) == 1 {
if bytes.buffer_write_byte(buf, data[0]) != nil { if bytes.buffer_write_byte(buf, data[0]) != nil {
return compress.General_Error.Resize_Failed return .Resize_Failed
} }
} else if n, _ := bytes.buffer_write(buf, data); n != len(data) { } else if n, _ := bytes.buffer_write(buf, data); n != len(data) {
return compress.General_Error.Resize_Failed return .Resize_Failed
} }
return nil return nil
} }
+24 -37
View File
@@ -9,8 +9,6 @@ import "core:strconv"
import "core:strings" import "core:strings"
import "core:unicode" import "core:unicode"
Image :: image.Image Image :: image.Image
Format :: image.Netpbm_Format Format :: image.Netpbm_Format
Header :: image.Netpbm_Header Header :: image.Netpbm_Header
@@ -18,8 +16,6 @@ Info :: image.Netpbm_Info
Error :: image.Error Error :: image.Error
Format_Error :: image.Netpbm_Error Format_Error :: image.Netpbm_Error
Formats :: bit_set[Format] Formats :: bit_set[Format]
PBM :: Formats{.P1, .P4} PBM :: Formats{.P1, .P4}
PGM :: Formats{.P2, .P5} PGM :: Formats{.P2, .P5}
@@ -30,14 +26,12 @@ PFM :: Formats{.Pf, .PF}
ASCII :: Formats{.P1, .P2, .P3} ASCII :: Formats{.P1, .P2, .P3}
BINARY :: Formats{.P4, .P5, .P6} + PAM + PFM BINARY :: Formats{.P4, .P5, .P6} + PAM + PFM
load :: proc {
load_from_file,
read :: proc { load_from_buffer,
read_from_file,
read_from_buffer,
} }
read_from_file :: proc(filename: string, allocator := context.allocator) -> (img: Image, err: Error) { load_from_file :: proc(filename: string, allocator := context.allocator) -> (img: Image, err: Error) {
context.allocator = allocator context.allocator = allocator
data, ok := os.read_entire_file(filename); defer delete(data) data, ok := os.read_entire_file(filename); defer delete(data)
@@ -49,7 +43,7 @@ read_from_file :: proc(filename: string, allocator := context.allocator) -> (img
return read_from_buffer(data) return read_from_buffer(data)
} }
read_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: Image, err: Error) { load_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: Image, err: Error) {
context.allocator = allocator context.allocator = allocator
header: Header; defer header_destroy(&header) header: Header; defer header_destroy(&header)
@@ -70,14 +64,12 @@ read_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img:
return return
} }
save :: proc {
save_to_file,
write :: proc { save_to_buffer,
write_to_file,
write_to_buffer,
} }
write_to_file :: proc(filename: string, img: Image, allocator := context.allocator) -> (err: Error) { save_to_file :: proc(filename: string, img: Image, allocator := context.allocator) -> (err: Error) {
context.allocator = allocator context.allocator = allocator
data: []byte; defer delete(data) data: []byte; defer delete(data)
@@ -90,7 +82,7 @@ write_to_file :: proc(filename: string, img: Image, allocator := context.allocat
return Format_Error.None return Format_Error.None
} }
write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: []byte, err: Error) { save_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer: []byte, err: Error) {
context.allocator = allocator context.allocator = allocator
info, ok := img.metadata.(^image.Netpbm_Info) info, ok := img.metadata.(^image.Netpbm_Info)
@@ -109,12 +101,12 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer:
} }
if header.format in (PNM + PAM) { if header.format in (PNM + PAM) {
if header.maxval <= int(max(u8)) && img.depth != 1 \ if header.maxval <= int(max(u8)) && img.depth != 8 \
|| header.maxval > int(max(u8)) && header.maxval <= int(max(u16)) && img.depth != 2 { || header.maxval > int(max(u8)) && header.maxval <= int(max(u16)) && img.depth != 16 {
err = Format_Error.Invalid_Image_Depth err = Format_Error.Invalid_Image_Depth
return return
} }
} else if header.format in PFM && img.depth != 4 { } else if header.format in PFM && img.depth != 32 {
err = Format_Error.Invalid_Image_Depth err = Format_Error.Invalid_Image_Depth
return return
} }
@@ -179,7 +171,7 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer:
mem.copy(raw_data(data.buf[len(header_buf):]), raw_data(pixels), len(pixels)) mem.copy(raw_data(data.buf[len(header_buf):]), raw_data(pixels), len(pixels))
// convert from native endianness // convert from native endianness
if img.depth == 2 { if img.depth == 16 {
pixels := mem.slice_data_cast([]u16be, data.buf[len(header_buf):]) pixels := mem.slice_data_cast([]u16be, data.buf[len(header_buf):])
for p in &pixels { for p in &pixels {
p = u16be(transmute(u16) p) p = u16be(transmute(u16) p)
@@ -212,7 +204,7 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer:
// Token ASCII // Token ASCII
case .P2, .P3: case .P2, .P3:
switch img.depth { switch img.depth {
case 1: case 8:
pixels := img.pixels.buf[:] pixels := img.pixels.buf[:]
for y in 0 ..< img.height { for y in 0 ..< img.height {
for x in 0 ..< img.width { for x in 0 ..< img.width {
@@ -226,7 +218,7 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer:
fmt.sbprint(&data, "\n") fmt.sbprint(&data, "\n")
} }
case 2: case 16:
pixels := mem.slice_data_cast([]u16, img.pixels.buf[:]) pixels := mem.slice_data_cast([]u16, img.pixels.buf[:])
for y in 0 ..< img.height { for y in 0 ..< img.height {
for x in 0 ..< img.width { for x in 0 ..< img.width {
@@ -251,8 +243,6 @@ write_to_buffer :: proc(img: Image, allocator := context.allocator) -> (buffer:
return data.buf[:], Format_Error.None return data.buf[:], Format_Error.None
} }
parse_header :: proc(data: []byte, allocator := context.allocator) -> (header: Header, length: int, err: Error) { parse_header :: proc(data: []byte, allocator := context.allocator) -> (header: Header, length: int, err: Error) {
context.allocator = allocator context.allocator = allocator
@@ -351,7 +341,7 @@ _parse_header_pnm :: proc(data: []byte) -> (header: Header, length: int, err: Er
// set extra info // set extra info
header.channels = 3 if header.format in PPM else 1 header.channels = 3 if header.format in PPM else 1
header.depth = 2 if header.maxval > int(max(u8)) else 1 header.depth = 16 if header.maxval > int(max(u8)) else 8
// limit checking // limit checking
if current_field < len(header_fields) { if current_field < len(header_fields) {
@@ -448,12 +438,11 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head
} }
// extra info // extra info
header.depth = 2 if header.maxval > int(max(u8)) else 1 header.depth = 16 if header.maxval > int(max(u8)) else 8
// limit checking // limit checking
if header.width < 1 \ if header.width < 1 \
|| header.height < 1 \ || header.height < 1 \
|| header.depth < 1 \
|| header.maxval < 1 \ || header.maxval < 1 \
|| header.maxval > int(max(u16)) { || header.maxval > int(max(u16)) {
err = Format_Error.Invalid_Header_Value err = Format_Error.Invalid_Header_Value
@@ -484,7 +473,7 @@ _parse_header_pfm :: proc(data: []byte) -> (header: Header, length: int, err: Er
} }
// floating point // floating point
header.depth = 4 header.depth = 32
// width // width
field, ok = strings.fields_iterator(&field_iterator) field, ok = strings.fields_iterator(&field_iterator)
@@ -542,8 +531,6 @@ _parse_header_pfm :: proc(data: []byte) -> (header: Header, length: int, err: Er
return return
} }
decode_image :: proc(header: Header, data: []byte, allocator := context.allocator) -> (img: Image, err: Error) { decode_image :: proc(header: Header, data: []byte, allocator := context.allocator) -> (img: Image, err: Error) {
context.allocator = allocator context.allocator = allocator
@@ -554,7 +541,7 @@ decode_image :: proc(header: Header, data: []byte, allocator := context.allocato
depth = header.depth, depth = header.depth,
} }
buffer_size := img.width * img.height * img.channels * img.depth buffer_size := image.compute_buffer_size(img.width, img.height, img.channels, img.depth)
// we can check data size for binary formats // we can check data size for binary formats
if header.format in BINARY { if header.format in BINARY {
@@ -615,7 +602,7 @@ decode_image :: proc(header: Header, data: []byte, allocator := context.allocato
} }
} }
} else { } else {
if img.depth == 2 { if img.depth == 16 {
pixels := mem.slice_data_cast([]u16, img.pixels.buf[:]) pixels := mem.slice_data_cast([]u16, img.pixels.buf[:])
for p in &pixels { for p in &pixels {
p = u16(transmute(u16be) p) p = u16(transmute(u16be) p)
@@ -658,9 +645,9 @@ decode_image :: proc(header: Header, data: []byte, allocator := context.allocato
} }
switch img.depth { switch img.depth {
case 1: case 8:
bytes.buffer_write_byte(&img.pixels, u8(value)) bytes.buffer_write_byte(&img.pixels, u8(value))
case 2: case 16:
vb := transmute([2]u8) u16(value) vb := transmute([2]u8) u16(value)
bytes.buffer_write(&img.pixels, vb[:]) bytes.buffer_write(&img.pixels, vb[:])
} }
@@ -678,4 +665,4 @@ decode_image :: proc(header: Header, data: []byte, allocator := context.allocato
err = Format_Error.None err = Format_Error.None
return return
} }
+8 -8
View File
@@ -238,7 +238,7 @@ append_chunk :: proc(list: ^[dynamic]image.PNG_Chunk, src: image.PNG_Chunk, allo
append(list, c) append(list, c)
if len(list) != length + 1 { if len(list) != length + 1 {
// Resize during append failed. // Resize during append failed.
return mem.Allocator_Error.Out_Of_Memory return .Unable_To_Allocate_Or_Resize
} }
return return
@@ -347,7 +347,7 @@ load_from_file :: proc(filename: string, options := Options{}, allocator := cont
return load_from_slice(data, options) return load_from_slice(data, options)
} else { } else {
img = new(Image) img = new(Image)
return img, compress.General_Error.File_Not_Found return img, .Unable_To_Read_File
} }
} }
@@ -381,7 +381,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
signature, io_error := compress.read_data(ctx, Signature) signature, io_error := compress.read_data(ctx, Signature)
if io_error != .None || signature != .PNG { if io_error != .None || signature != .PNG {
return img, .Invalid_PNG_Signature return img, .Invalid_Signature
} }
idat: []u8 idat: []u8
@@ -747,7 +747,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8) dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8)
t := bytes.Buffer{} t := bytes.Buffer{}
if !resize(&t.buf, dest_raw_size) { if !resize(&t.buf, dest_raw_size) {
return {}, mem.Allocator_Error.Out_Of_Memory return {}, .Unable_To_Allocate_Or_Resize
} }
i := 0; j := 0 i := 0; j := 0
@@ -828,7 +828,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 16) dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 16)
t := bytes.Buffer{} t := bytes.Buffer{}
if !resize(&t.buf, dest_raw_size) { if !resize(&t.buf, dest_raw_size) {
return {}, mem.Allocator_Error.Out_Of_Memory return {}, .Unable_To_Allocate_Or_Resize
} }
p16 := mem.slice_data_cast([]u16, temp.buf[:]) p16 := mem.slice_data_cast([]u16, temp.buf[:])
@@ -1027,7 +1027,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8) dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8)
t := bytes.Buffer{} t := bytes.Buffer{}
if !resize(&t.buf, dest_raw_size) { if !resize(&t.buf, dest_raw_size) {
return {}, mem.Allocator_Error.Out_Of_Memory return {}, .Unable_To_Allocate_Or_Resize
} }
p := mem.slice_data_cast([]u8, temp.buf[:]) p := mem.slice_data_cast([]u8, temp.buf[:])
@@ -1535,7 +1535,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
num_bytes := compute_buffer_size(width, height, channels, depth == 16 ? 16 : 8) num_bytes := compute_buffer_size(width, height, channels, depth == 16 ? 16 : 8)
if !resize(&img.pixels.buf, num_bytes) { if !resize(&img.pixels.buf, num_bytes) {
return mem.Allocator_Error.Out_Of_Memory return .Unable_To_Allocate_Or_Resize
} }
filter_ok: bool filter_ok: bool
@@ -1577,7 +1577,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
temp: bytes.Buffer temp: bytes.Buffer
temp_len := compute_buffer_size(x, y, channels, depth == 16 ? 16 : 8) temp_len := compute_buffer_size(x, y, channels, depth == 16 ? 16 : 8)
if !resize(&temp.buf, temp_len) { if !resize(&temp.buf, temp_len) {
return mem.Allocator_Error.Out_Of_Memory return .Unable_To_Allocate_Or_Resize
} }
params := Filter_Params{ params := Filter_Params{
+5 -7
View File
@@ -12,14 +12,12 @@
// The QOI specification is at https://qoiformat.org. // The QOI specification is at https://qoiformat.org.
package qoi package qoi
import "core:mem"
import "core:image" import "core:image"
import "core:compress" import "core:compress"
import "core:bytes" import "core:bytes"
import "core:os" import "core:os"
Error :: image.Error Error :: image.Error
General :: compress.General_Error
Image :: image.Image Image :: image.Image
Options :: image.Options Options :: image.Options
@@ -57,7 +55,7 @@ save_to_memory :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
max_size := pixels * (img.channels + 1) + size_of(image.QOI_Header) + size_of(u64be) max_size := pixels * (img.channels + 1) + size_of(image.QOI_Header) + size_of(u64be)
if !resize(&output.buf, max_size) { if !resize(&output.buf, max_size) {
return General.Resize_Failed return .Unable_To_Allocate_Or_Resize
} }
header := image.QOI_Header{ header := image.QOI_Header{
@@ -177,7 +175,7 @@ save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocato
save_to_memory(out, img, options) or_return save_to_memory(out, img, options) or_return
write_ok := os.write_entire_file(output, out.buf[:]) write_ok := os.write_entire_file(output, out.buf[:])
return nil if write_ok else General.Cannot_Open_File return nil if write_ok else .Unable_To_Write_File
} }
save :: proc{save_to_memory, save_to_file} save :: proc{save_to_memory, save_to_file}
@@ -201,7 +199,7 @@ load_from_file :: proc(filename: string, options := Options{}, allocator := cont
return load_from_slice(data, options) return load_from_slice(data, options)
} else { } else {
img = new(Image) img = new(Image)
return img, compress.General_Error.File_Not_Found return img, .Unable_To_Read_File
} }
} }
@@ -221,7 +219,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
header := image.read_data(ctx, image.QOI_Header) or_return header := image.read_data(ctx, image.QOI_Header) or_return
if header.magic != image.QOI_Magic { if header.magic != image.QOI_Magic {
return img, .Invalid_QOI_Signature return img, .Invalid_Signature
} }
if img == nil { if img == nil {
@@ -264,7 +262,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8) bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8)
if !resize(&img.pixels.buf, bytes_needed) { if !resize(&img.pixels.buf, bytes_needed) {
return img, mem.Allocator_Error.Out_Of_Memory return img, .Unable_To_Allocate_Or_Resize
} }
/* /*
+2 -3
View File
@@ -17,7 +17,6 @@ import "core:bytes"
import "core:os" import "core:os"
Error :: image.Error Error :: image.Error
General :: compress.General_Error
Image :: image.Image Image :: image.Image
Options :: image.Options Options :: image.Options
@@ -55,7 +54,7 @@ save_to_memory :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
necessary := pixels * img.channels + size_of(image.TGA_Header) necessary := pixels * img.channels + size_of(image.TGA_Header)
if !resize(&output.buf, necessary) { if !resize(&output.buf, necessary) {
return General.Resize_Failed return .Unable_To_Allocate_Or_Resize
} }
header := image.TGA_Header{ header := image.TGA_Header{
@@ -97,7 +96,7 @@ save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocato
save_to_memory(out, img, options) or_return save_to_memory(out, img, options) or_return
write_ok := os.write_entire_file(output, out.buf[:]) write_ok := os.write_entire_file(output, out.buf[:])
return nil if write_ok else General.Cannot_Open_File return nil if write_ok else .Unable_To_Write_File
} }
save :: proc{save_to_memory, save_to_file} save :: proc{save_to_memory, save_to_file}
+6 -6
View File
@@ -1199,37 +1199,37 @@ Corrupt_PNG_Tests := []PNG_Test{
{ {
"xs1n0g01", // signature byte 1 MSBit reset to zero "xs1n0g01", // signature byte 1 MSBit reset to zero
{ {
{Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, {Default, .Invalid_Signature, {}, 0x_0000_0000},
}, },
}, },
{ {
"xs2n0g01", // signature byte 2 is a 'Q' "xs2n0g01", // signature byte 2 is a 'Q'
{ {
{Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, {Default, .Invalid_Signature, {}, 0x_0000_0000},
}, },
}, },
{ {
"xs4n0g01", // signature byte 4 lowercase "xs4n0g01", // signature byte 4 lowercase
{ {
{Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, {Default, .Invalid_Signature, {}, 0x_0000_0000},
}, },
}, },
{ {
"xs7n0g01", // 7th byte a space instead of control-Z "xs7n0g01", // 7th byte a space instead of control-Z
{ {
{Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, {Default, .Invalid_Signature, {}, 0x_0000_0000},
}, },
}, },
{ {
"xcrn0g04", // added cr bytes "xcrn0g04", // added cr bytes
{ {
{Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, {Default, .Invalid_Signature, {}, 0x_0000_0000},
}, },
}, },
{ {
"xlfn0g04", // added lf bytes "xlfn0g04", // added lf bytes
{ {
{Default, .Invalid_PNG_Signature, {}, 0x_0000_0000}, {Default, .Invalid_Signature, {}, 0x_0000_0000},
}, },
}, },
{ {