mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-23 07:57:52 +00:00
Minor formatting changes
This commit is contained in:
@@ -145,7 +145,7 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
||||
mem.zero_slice(sizes[:]);
|
||||
mem.zero_slice(z.fast[:]);
|
||||
|
||||
for v, _ in code_lengths {
|
||||
for v in code_lengths {
|
||||
sizes[v] += 1;
|
||||
}
|
||||
sizes[0] = 0;
|
||||
@@ -163,7 +163,7 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
||||
z.firstsymbol[i] = u16(k);
|
||||
code = code + sizes[i];
|
||||
if sizes[i] != 0 {
|
||||
if (code - 1 >= (1 << u16(i))) {
|
||||
if code - 1 >= (1 << u16(i)) {
|
||||
return E_Deflate.Huffman_Bad_Code_Lengths;
|
||||
}
|
||||
}
|
||||
@@ -181,7 +181,7 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
||||
fastv := u16((u16(v) << 9) | u16(ci));
|
||||
z.size[c] = u8(v);
|
||||
z.value[c] = u16(ci);
|
||||
if (v <= ZFAST_BITS) {
|
||||
if v <= ZFAST_BITS {
|
||||
j := z_bit_reverse(u16(next_code[v]), v);
|
||||
for j < (1 << ZFAST_BITS) {
|
||||
z.fast[j] = fastv;
|
||||
@@ -195,15 +195,10 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
||||
}
|
||||
|
||||
decode_huffman_slowpath :: proc(z: ^Context, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
|
||||
r = 0;
|
||||
err = nil;
|
||||
|
||||
k: int;
|
||||
s: u8;
|
||||
|
||||
code := u16(compress.peek_bits_lsb(z, 16));
|
||||
|
||||
k = int(z_bit_reverse(code, 16));
|
||||
k := int(z_bit_reverse(code, 16));
|
||||
s: u8;
|
||||
|
||||
#no_bounds_check for s = HUFFMAN_FAST_BITS+1; ; {
|
||||
if k < t.maxcode[s] {
|
||||
@@ -211,7 +206,7 @@ decode_huffman_slowpath :: proc(z: ^Context, t: ^Huffman_Table) -> (r: u16, err:
|
||||
}
|
||||
s += 1;
|
||||
}
|
||||
if (s >= 16) {
|
||||
if s >= 16 {
|
||||
return 0, E_Deflate.Bad_Huffman_Code;
|
||||
}
|
||||
// code size is s, so:
|
||||
|
||||
+26
-28
@@ -127,7 +127,6 @@ Error :: enum {
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -144,7 +143,6 @@ Channel :: enum u8 {
|
||||
}
|
||||
|
||||
return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok: bool) {
|
||||
|
||||
ok = false;
|
||||
t: bytes.Buffer;
|
||||
|
||||
@@ -159,36 +157,36 @@ return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok
|
||||
return {}, false;
|
||||
}
|
||||
|
||||
switch(img.depth) {
|
||||
case 8:
|
||||
buffer_size := compute_buffer_size(img.width, img.height, 1, 8);
|
||||
t = bytes.Buffer{};
|
||||
resize(&t.buf, buffer_size);
|
||||
switch img.depth {
|
||||
case 8:
|
||||
buffer_size := compute_buffer_size(img.width, img.height, 1, 8);
|
||||
t = bytes.Buffer{};
|
||||
resize(&t.buf, buffer_size);
|
||||
|
||||
i := bytes.buffer_to_bytes(&img.pixels);
|
||||
o := bytes.buffer_to_bytes(&t);
|
||||
i := bytes.buffer_to_bytes(&img.pixels);
|
||||
o := bytes.buffer_to_bytes(&t);
|
||||
|
||||
for len(i) > 0 {
|
||||
o[0] = i[idx];
|
||||
i = i[img.channels:];
|
||||
o = o[1:];
|
||||
}
|
||||
case 16:
|
||||
buffer_size := compute_buffer_size(img.width, img.height, 2, 8);
|
||||
t = bytes.Buffer{};
|
||||
resize(&t.buf, buffer_size);
|
||||
for len(i) > 0 {
|
||||
o[0] = i[idx];
|
||||
i = i[img.channels:];
|
||||
o = o[1:];
|
||||
}
|
||||
case 16:
|
||||
buffer_size := compute_buffer_size(img.width, img.height, 2, 8);
|
||||
t = bytes.Buffer{};
|
||||
resize(&t.buf, buffer_size);
|
||||
|
||||
i := mem.slice_data_cast([]u16, img.pixels.buf[:]);
|
||||
o := mem.slice_data_cast([]u16, t.buf[:]);
|
||||
i := mem.slice_data_cast([]u16, img.pixels.buf[:]);
|
||||
o := mem.slice_data_cast([]u16, t.buf[:]);
|
||||
|
||||
for len(i) > 0 {
|
||||
o[0] = i[idx];
|
||||
i = i[img.channels:];
|
||||
o = o[1:];
|
||||
}
|
||||
case 1, 2, 4:
|
||||
// We shouldn't see this case, as the loader already turns these into 8-bit.
|
||||
return {}, false;
|
||||
for len(i) > 0 {
|
||||
o[0] = i[idx];
|
||||
i = i[img.channels:];
|
||||
o = o[1:];
|
||||
}
|
||||
case 1, 2, 4:
|
||||
// We shouldn't see this case, as the loader already turns these into 8-bit.
|
||||
return {}, false;
|
||||
}
|
||||
|
||||
res = new(Image);
|
||||
|
||||
+78
-78
@@ -35,86 +35,86 @@ main :: proc() {
|
||||
// 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:
|
||||
t, _ := png.core_time(c);
|
||||
fmt.printf("[tIME]: %v\n", t);
|
||||
case .gAMA:
|
||||
fmt.printf("[gAMA]: %v\n", png.gamma(c));
|
||||
case .pHYs:
|
||||
phys := png.phys(c);
|
||||
if phys.unit == .Meter {
|
||||
xm := f32(img.width) / f32(phys.ppu_x);
|
||||
ym := f32(img.height) / f32(phys.ppu_y);
|
||||
dpi_x, dpi_y := png.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);
|
||||
#partial switch c.header.type {
|
||||
case .tIME:
|
||||
t, _ := png.core_time(c);
|
||||
fmt.printf("[tIME]: %v\n", t);
|
||||
case .gAMA:
|
||||
fmt.printf("[gAMA]: %v\n", png.gamma(c));
|
||||
case .pHYs:
|
||||
phys := png.phys(c);
|
||||
if phys.unit == .Meter {
|
||||
xm := f32(img.width) / f32(phys.ppu_x);
|
||||
ym := f32(img.height) / f32(phys.ppu_y);
|
||||
dpi_x, dpi_y := png.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 := png.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("[pHYs] x: %v, y: %v pixels per unknown unit.\n", phys.ppu_x, phys.ppu_y);
|
||||
fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text);
|
||||
}
|
||||
case .iTXt, .zTXt, .tEXt:
|
||||
res, ok_text := png.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 png.text_destroy(res);
|
||||
case .bKGD:
|
||||
fmt.printf("[bKGD] %v\n", img.background);
|
||||
case .eXIf:
|
||||
res, ok_exif := png.exif(c);
|
||||
if 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:
|
||||
plte, plte_ok := png.plte(c);
|
||||
if plte_ok {
|
||||
fmt.printf("[PLTE] %v\n", plte);
|
||||
} else {
|
||||
fmt.printf("[PLTE] Error\n");
|
||||
}
|
||||
case .hIST:
|
||||
res, ok_hist := png.hist(c);
|
||||
if ok_hist {
|
||||
fmt.printf("[hIST] %v\n", res);
|
||||
}
|
||||
case .cHRM:
|
||||
res, ok_chrm := png.chrm(c);
|
||||
if ok_chrm {
|
||||
fmt.printf("[cHRM] %v\n", res);
|
||||
}
|
||||
case .sPLT:
|
||||
res, ok_splt := png.splt(c);
|
||||
if ok_splt {
|
||||
fmt.printf("[sPLT] %v\n", res);
|
||||
}
|
||||
png.splt_destroy(res);
|
||||
case .sBIT:
|
||||
if res, ok_sbit := png.sbit(c); ok_sbit {
|
||||
fmt.printf("[sBIT] %v\n", res);
|
||||
}
|
||||
case .iCCP:
|
||||
res, ok_iccp := png.iccp(c);
|
||||
if ok_iccp {
|
||||
fmt.printf("[iCCP] %v\n", res);
|
||||
}
|
||||
png.iccp_destroy(res);
|
||||
case .sRGB:
|
||||
if res, ok_srgb := png.srgb(c); ok_srgb {
|
||||
fmt.printf("[sRGB] Rendering intent: %v\n", res);
|
||||
}
|
||||
case:
|
||||
type := c.header.type;
|
||||
name := png.chunk_type_to_name(&type);
|
||||
fmt.printf("[%v]: %v\n", name, c.data);
|
||||
}
|
||||
defer png.text_destroy(res);
|
||||
case .bKGD:
|
||||
fmt.printf("[bKGD] %v\n", img.background);
|
||||
case .eXIf:
|
||||
res, ok_exif := png.exif(c);
|
||||
if 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:
|
||||
plte, plte_ok := png.plte(c);
|
||||
if plte_ok {
|
||||
fmt.printf("[PLTE] %v\n", plte);
|
||||
} else {
|
||||
fmt.printf("[PLTE] Error\n");
|
||||
}
|
||||
case .hIST:
|
||||
res, ok_hist := png.hist(c);
|
||||
if ok_hist {
|
||||
fmt.printf("[hIST] %v\n", res);
|
||||
}
|
||||
case .cHRM:
|
||||
res, ok_chrm := png.chrm(c);
|
||||
if ok_chrm {
|
||||
fmt.printf("[cHRM] %v\n", res);
|
||||
}
|
||||
case .sPLT:
|
||||
res, ok_splt := png.splt(c);
|
||||
if ok_splt {
|
||||
fmt.printf("[sPLT] %v\n", res);
|
||||
}
|
||||
png.splt_destroy(res);
|
||||
case .sBIT:
|
||||
if res, ok_sbit := png.sbit(c); ok_sbit {
|
||||
fmt.printf("[sBIT] %v\n", res);
|
||||
}
|
||||
case .iCCP:
|
||||
res, ok_iccp := png.iccp(c);
|
||||
if ok_iccp {
|
||||
fmt.printf("[iCCP] %v\n", res);
|
||||
}
|
||||
png.iccp_destroy(res);
|
||||
case .sRGB:
|
||||
if res, ok_srgb := png.srgb(c); ok_srgb {
|
||||
fmt.printf("[sRGB] Rendering intent: %v\n", res);
|
||||
}
|
||||
case:
|
||||
type := c.header.type;
|
||||
name := png.chunk_type_to_name(&type);
|
||||
fmt.printf("[%v]: %v\n", name, c.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ core_time :: proc(c: Chunk) -> (t: coretime.Time, ok: bool) {
|
||||
}
|
||||
|
||||
text :: proc(c: Chunk) -> (res: Text, ok: bool) {
|
||||
#partial switch c.header.type {
|
||||
#partial switch c.header.type {
|
||||
case .tEXt:
|
||||
ok = true;
|
||||
|
||||
|
||||
+261
-265
@@ -115,11 +115,11 @@ Interlace_Method :: enum u8 {
|
||||
}
|
||||
|
||||
Row_Filter :: enum u8 {
|
||||
None = 0,
|
||||
Sub = 1,
|
||||
Up = 2,
|
||||
Average = 3,
|
||||
Paeth = 4,
|
||||
None = 0,
|
||||
Sub = 1,
|
||||
Up = 2,
|
||||
Average = 3,
|
||||
Paeth = 4,
|
||||
};
|
||||
|
||||
PLTE_Entry :: [3]u8;
|
||||
@@ -166,18 +166,18 @@ CIE_1931 :: struct #packed {
|
||||
}
|
||||
|
||||
cHRM_Raw :: struct #packed {
|
||||
w: CIE_1931_Raw,
|
||||
r: CIE_1931_Raw,
|
||||
g: CIE_1931_Raw,
|
||||
b: CIE_1931_Raw,
|
||||
w: CIE_1931_Raw,
|
||||
r: CIE_1931_Raw,
|
||||
g: CIE_1931_Raw,
|
||||
b: CIE_1931_Raw,
|
||||
}
|
||||
#assert(size_of(cHRM_Raw) == 32);
|
||||
|
||||
cHRM :: struct #packed {
|
||||
w: CIE_1931,
|
||||
r: CIE_1931,
|
||||
g: CIE_1931,
|
||||
b: CIE_1931,
|
||||
w: CIE_1931,
|
||||
r: CIE_1931,
|
||||
g: CIE_1931,
|
||||
b: CIE_1931,
|
||||
}
|
||||
#assert(size_of(cHRM) == 32);
|
||||
|
||||
@@ -236,10 +236,7 @@ ADAM7_Y_SPACING := []int{ 8,8,8,4,4,2,2 };
|
||||
|
||||
// Implementation starts here
|
||||
|
||||
read_chunk :: proc(ctx: ^compress.Context) -> (Chunk, Error) {
|
||||
|
||||
chunk := Chunk{};
|
||||
|
||||
read_chunk :: proc(ctx: ^compress.Context) -> (chunk: Chunk, err: Error) {
|
||||
ch, e := compress.read_data(ctx, Chunk_Header);
|
||||
if e != .None {
|
||||
return {}, E_General.Stream_Too_Short;
|
||||
@@ -271,7 +268,6 @@ read_chunk :: proc(ctx: ^compress.Context) -> (Chunk, Error) {
|
||||
}
|
||||
|
||||
read_header :: proc(ctx: ^compress.Context) -> (IHDR, Error) {
|
||||
|
||||
c, e := read_chunk(ctx);
|
||||
if e != nil {
|
||||
return {}, e;
|
||||
@@ -297,48 +293,48 @@ read_header :: proc(ctx: ^compress.Context) -> (IHDR, Error) {
|
||||
|
||||
}
|
||||
|
||||
switch (transmute(u8)color_type) {
|
||||
case 0:
|
||||
/*
|
||||
Grayscale.
|
||||
Allowed bit depths: 1, 2, 4, 8 and 16.
|
||||
*/
|
||||
allowed := false;
|
||||
for i in ([]u8{1, 2, 4, 8, 16}) {
|
||||
if bit_depth == i {
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
switch transmute(u8)color_type {
|
||||
case 0:
|
||||
/*
|
||||
Grayscale.
|
||||
Allowed bit depths: 1, 2, 4, 8 and 16.
|
||||
*/
|
||||
allowed := false;
|
||||
for i in ([]u8{1, 2, 4, 8, 16}) {
|
||||
if bit_depth == i {
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
if !allowed {
|
||||
return {}, E_PNG.Invalid_Color_Bit_Depth_Combo;
|
||||
}
|
||||
case 2, 4, 6:
|
||||
/*
|
||||
RGB, Grayscale+Alpha, RGBA.
|
||||
Allowed bit depths: 8 and 16
|
||||
*/
|
||||
if bit_depth != 8 && bit_depth != 16 {
|
||||
return {}, E_PNG.Invalid_Color_Bit_Depth_Combo;
|
||||
}
|
||||
case 3:
|
||||
/*
|
||||
Paletted. PLTE chunk must appear.
|
||||
Allowed bit depths: 1, 2, 4 and 8.
|
||||
*/
|
||||
allowed := false;
|
||||
for i in ([]u8{1, 2, 4, 8}) {
|
||||
if bit_depth == i {
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !allowed {
|
||||
return {}, E_PNG.Invalid_Color_Bit_Depth_Combo;
|
||||
}
|
||||
if !allowed {
|
||||
return {}, E_PNG.Invalid_Color_Bit_Depth_Combo;
|
||||
}
|
||||
case 2, 4, 6:
|
||||
/*
|
||||
RGB, Grayscale+Alpha, RGBA.
|
||||
Allowed bit depths: 8 and 16
|
||||
*/
|
||||
if bit_depth != 8 && bit_depth != 16 {
|
||||
return {}, E_PNG.Invalid_Color_Bit_Depth_Combo;
|
||||
}
|
||||
case 3:
|
||||
/*
|
||||
Paletted. PLTE chunk must appear.
|
||||
Allowed bit depths: 1, 2, 4 and 8.
|
||||
*/
|
||||
allowed := false;
|
||||
for i in ([]u8{1, 2, 4, 8}) {
|
||||
if bit_depth == i {
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !allowed {
|
||||
return {}, E_PNG.Invalid_Color_Bit_Depth_Combo;
|
||||
}
|
||||
|
||||
case:
|
||||
return {}, E_PNG.Unknown_Color_Type;
|
||||
case:
|
||||
return {}, E_PNG.Unknown_Color_Type;
|
||||
}
|
||||
|
||||
return header, nil;
|
||||
@@ -398,11 +394,11 @@ load_from_stream :: proc(stream: io.Stream, options := Options{}, allocator := c
|
||||
|
||||
img.sidecar = nil;
|
||||
|
||||
ctx := compress.Context{
|
||||
ctx := &compress.Context{
|
||||
input = stream,
|
||||
};
|
||||
|
||||
signature, io_error := compress.read_data(&ctx, Signature);
|
||||
signature, io_error := compress.read_data(ctx, Signature);
|
||||
if io_error != .None || signature != .PNG {
|
||||
return img, E_PNG.Invalid_PNG_Signature;
|
||||
}
|
||||
@@ -435,225 +431,225 @@ load_from_stream :: proc(stream: io.Stream, options := Options{}, allocator := c
|
||||
|
||||
read_error: io.Error;
|
||||
// 12 bytes is the size of a chunk with a zero-length payload.
|
||||
for (read_error == .None && !seen_iend) {
|
||||
for read_error == .None && !seen_iend {
|
||||
// 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, Chunk_Header);
|
||||
if e != .None {
|
||||
return img, E_General.Stream_Too_Short;
|
||||
}
|
||||
// name := chunk_type_to_name(&ch.type); // Only used for debug prints during development.
|
||||
|
||||
#partial switch(ch.type) {
|
||||
case .IHDR:
|
||||
if seen_ihdr || !first {
|
||||
return {}, E_PNG.IHDR_Not_First_Chunk;
|
||||
}
|
||||
seen_ihdr = true;
|
||||
case .IHDR:
|
||||
if seen_ihdr || !first {
|
||||
return {}, E_PNG.IHDR_Not_First_Chunk;
|
||||
}
|
||||
seen_ihdr = true;
|
||||
|
||||
header, err = read_header(&ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
header, err = read_header(ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
|
||||
if .Paletted in header.color_type {
|
||||
// Color type 3
|
||||
img.channels = 1;
|
||||
final_image_channels = 3;
|
||||
img.depth = 8;
|
||||
} else if .Color in header.color_type {
|
||||
// Color image without a palette
|
||||
img.channels = 3;
|
||||
final_image_channels = 3;
|
||||
img.depth = header.bit_depth;
|
||||
} else {
|
||||
// Grayscale
|
||||
img.channels = 1;
|
||||
final_image_channels = 1;
|
||||
img.depth = header.bit_depth;
|
||||
}
|
||||
|
||||
if .Alpha in header.color_type {
|
||||
img.channels += 1;
|
||||
final_image_channels += 1;
|
||||
}
|
||||
|
||||
if img.channels == 0 || img.depth == 0 {
|
||||
return {}, E_PNG.IHDR_Corrupt;
|
||||
}
|
||||
|
||||
img.width = int(header.width);
|
||||
img.height = int(header.height);
|
||||
|
||||
using header;
|
||||
h := IHDR{
|
||||
width = width,
|
||||
height = height,
|
||||
bit_depth = bit_depth,
|
||||
color_type = color_type,
|
||||
compression_method = compression_method,
|
||||
filter_method = filter_method,
|
||||
interlace_method = interlace_method,
|
||||
};
|
||||
info.header = h;
|
||||
case .PLTE:
|
||||
seen_plte = true;
|
||||
// PLTE must appear before IDAT and can't appear for color types 0, 4.
|
||||
ct := transmute(u8)info.header.color_type;
|
||||
if seen_idat || ct == 0 || ct == 4 {
|
||||
return img, E_PNG.PLTE_Encountered_Unexpectedly;
|
||||
}
|
||||
|
||||
c, err = read_chunk(&ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
|
||||
if c.header.length % 3 != 0 || c.header.length > 768 {
|
||||
return img, E_PNG.PLTE_Invalid_Length;
|
||||
}
|
||||
plte_ok: bool;
|
||||
_plte, plte_ok = plte(c);
|
||||
if !plte_ok {
|
||||
return img, E_PNG.PLTE_Invalid_Length;
|
||||
}
|
||||
|
||||
if .return_metadata in options {
|
||||
append(&info.chunks, c);
|
||||
}
|
||||
case .IDAT:
|
||||
// If we only want image metadata and don't want the pixel data, we can early out.
|
||||
if .return_metadata not_in options && .do_not_decompress_image in options {
|
||||
img.channels = final_image_channels;
|
||||
img.sidecar = info;
|
||||
return img, nil;
|
||||
}
|
||||
// There must be at least 1 IDAT, contiguous if more.
|
||||
if seen_idat {
|
||||
return img, E_PNG.IDAT_Must_Be_Contiguous;
|
||||
}
|
||||
|
||||
if idat_length > 0 {
|
||||
return img, E_PNG.IDAT_Must_Be_Contiguous;
|
||||
}
|
||||
|
||||
next := ch.type;
|
||||
for next == .IDAT {
|
||||
c, err = read_chunk(&ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
|
||||
bytes.buffer_write(&idat_b, c.data);
|
||||
idat_length += c.header.length;
|
||||
|
||||
ch, e = compress.peek_data(&ctx, Chunk_Header);
|
||||
if e != .None {
|
||||
return img, E_General.Stream_Too_Short;
|
||||
}
|
||||
next = ch.type;
|
||||
}
|
||||
idat = bytes.buffer_to_bytes(&idat_b);
|
||||
if int(idat_length) != len(idat) {
|
||||
return {}, E_PNG.IDAT_Corrupt;
|
||||
}
|
||||
seen_idat = true;
|
||||
case .IEND:
|
||||
c, err = read_chunk(&ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
seen_iend = true;
|
||||
case .bKGD:
|
||||
|
||||
// TODO: Make sure that 16-bit bKGD + tRNS chunks return u16 instead of u16be
|
||||
|
||||
c, err = read_chunk(&ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
seen_bkgd = true;
|
||||
if .return_metadata in options {
|
||||
append(&info.chunks, c);
|
||||
}
|
||||
|
||||
ct := transmute(u8)info.header.color_type;
|
||||
switch(ct) {
|
||||
case 3: // Indexed color
|
||||
if c.header.length != 1 {
|
||||
return {}, E_PNG.BKGD_Invalid_Length;
|
||||
}
|
||||
col := _plte.entries[c.data[0]];
|
||||
img.background = [3]u16{
|
||||
u16(col[0]) << 8 | u16(col[0]),
|
||||
u16(col[1]) << 8 | u16(col[1]),
|
||||
u16(col[2]) << 8 | u16(col[2]),
|
||||
};
|
||||
case 0, 4: // Grayscale, with and without Alpha
|
||||
if c.header.length != 2 {
|
||||
return {}, E_PNG.BKGD_Invalid_Length;
|
||||
}
|
||||
col := u16(mem.slice_data_cast([]u16be, c.data[:])[0]);
|
||||
img.background = [3]u16{col, col, col};
|
||||
case 2, 6: // Color, with and without Alpha
|
||||
if c.header.length != 6 {
|
||||
return {}, E_PNG.BKGD_Invalid_Length;
|
||||
}
|
||||
col := mem.slice_data_cast([]u16be, c.data[:]);
|
||||
img.background = [3]u16{u16(col[0]), u16(col[1]), u16(col[2])};
|
||||
}
|
||||
case .tRNS:
|
||||
c, err = read_chunk(&ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
|
||||
if .Alpha in info.header.color_type {
|
||||
return img, E_PNG.TRNS_Encountered_Unexpectedly;
|
||||
}
|
||||
|
||||
if .return_metadata in options {
|
||||
append(&info.chunks, c);
|
||||
}
|
||||
|
||||
/*
|
||||
This makes the image one with transparency, so set it to +1 here,
|
||||
even if we need we leave img.channels alone for the defilterer's
|
||||
sake. If we early because the user just cares about metadata,
|
||||
we'll set it to 'final_image_channels'.
|
||||
*/
|
||||
if .Paletted in header.color_type {
|
||||
// Color type 3
|
||||
img.channels = 1;
|
||||
final_image_channels = 3;
|
||||
img.depth = 8;
|
||||
} else if .Color in header.color_type {
|
||||
// Color image without a palette
|
||||
img.channels = 3;
|
||||
final_image_channels = 3;
|
||||
img.depth = header.bit_depth;
|
||||
} else {
|
||||
// Grayscale
|
||||
img.channels = 1;
|
||||
final_image_channels = 1;
|
||||
img.depth = header.bit_depth;
|
||||
}
|
||||
|
||||
if .Alpha in header.color_type {
|
||||
img.channels += 1;
|
||||
final_image_channels += 1;
|
||||
}
|
||||
|
||||
seen_trns = true;
|
||||
if info.header.bit_depth < 8 && .Paletted not_in info.header.color_type {
|
||||
// Rescale tRNS data so key matches intensity
|
||||
dsc := depth_scale_table;
|
||||
scale := dsc[info.header.bit_depth];
|
||||
if scale != 1 {
|
||||
key := mem.slice_data_cast([]u16be, c.data)[0] * u16be(scale);
|
||||
c.data = []u8{0, u8(key & 255)};
|
||||
}
|
||||
}
|
||||
trns = c;
|
||||
case .iDOT, .CbGI:
|
||||
/*
|
||||
iPhone PNG bastardization that doesn't adhere to spec with broken IDAT chunk.
|
||||
We're not going to add support for it. If you have the misfortunte of coming
|
||||
across one of these files, use a utility to defry it.s
|
||||
*/
|
||||
return img, E_PNG.PNG_Does_Not_Adhere_to_Spec;
|
||||
case:
|
||||
// Unhandled type
|
||||
c, err = read_chunk(&ctx);
|
||||
if img.channels == 0 || img.depth == 0 {
|
||||
return {}, E_PNG.IHDR_Corrupt;
|
||||
}
|
||||
|
||||
img.width = int(header.width);
|
||||
img.height = int(header.height);
|
||||
|
||||
using header;
|
||||
h := IHDR{
|
||||
width = width,
|
||||
height = height,
|
||||
bit_depth = bit_depth,
|
||||
color_type = color_type,
|
||||
compression_method = compression_method,
|
||||
filter_method = filter_method,
|
||||
interlace_method = interlace_method,
|
||||
};
|
||||
info.header = h;
|
||||
case .PLTE:
|
||||
seen_plte = true;
|
||||
// PLTE must appear before IDAT and can't appear for color types 0, 4.
|
||||
ct := transmute(u8)info.header.color_type;
|
||||
if seen_idat || ct == 0 || ct == 4 {
|
||||
return img, E_PNG.PLTE_Encountered_Unexpectedly;
|
||||
}
|
||||
|
||||
c, err = read_chunk(ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
|
||||
if c.header.length % 3 != 0 || c.header.length > 768 {
|
||||
return img, E_PNG.PLTE_Invalid_Length;
|
||||
}
|
||||
plte_ok: bool;
|
||||
_plte, plte_ok = plte(c);
|
||||
if !plte_ok {
|
||||
return img, E_PNG.PLTE_Invalid_Length;
|
||||
}
|
||||
|
||||
if .return_metadata in options {
|
||||
append(&info.chunks, c);
|
||||
}
|
||||
case .IDAT:
|
||||
// If we only want image metadata and don't want the pixel data, we can early out.
|
||||
if .return_metadata not_in options && .do_not_decompress_image in options {
|
||||
img.channels = final_image_channels;
|
||||
img.sidecar = info;
|
||||
return img, nil;
|
||||
}
|
||||
// There must be at least 1 IDAT, contiguous if more.
|
||||
if seen_idat {
|
||||
return img, E_PNG.IDAT_Must_Be_Contiguous;
|
||||
}
|
||||
|
||||
if idat_length > 0 {
|
||||
return img, E_PNG.IDAT_Must_Be_Contiguous;
|
||||
}
|
||||
|
||||
next := ch.type;
|
||||
for next == .IDAT {
|
||||
c, err = read_chunk(ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
if .return_metadata in options {
|
||||
// NOTE: Chunk cata is currently allocated on the temp allocator.
|
||||
append(&info.chunks, c);
|
||||
|
||||
bytes.buffer_write(&idat_b, c.data);
|
||||
idat_length += c.header.length;
|
||||
|
||||
ch, e = compress.peek_data(ctx, Chunk_Header);
|
||||
if e != .None {
|
||||
return img, E_General.Stream_Too_Short;
|
||||
}
|
||||
next = ch.type;
|
||||
}
|
||||
idat = bytes.buffer_to_bytes(&idat_b);
|
||||
if int(idat_length) != len(idat) {
|
||||
return {}, E_PNG.IDAT_Corrupt;
|
||||
}
|
||||
seen_idat = true;
|
||||
case .IEND:
|
||||
c, err = read_chunk(ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
seen_iend = true;
|
||||
case .bKGD:
|
||||
|
||||
// TODO: Make sure that 16-bit bKGD + tRNS chunks return u16 instead of u16be
|
||||
|
||||
c, err = read_chunk(ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
seen_bkgd = true;
|
||||
if .return_metadata in options {
|
||||
append(&info.chunks, c);
|
||||
}
|
||||
|
||||
ct := transmute(u8)info.header.color_type;
|
||||
switch(ct) {
|
||||
case 3: // Indexed color
|
||||
if c.header.length != 1 {
|
||||
return {}, E_PNG.BKGD_Invalid_Length;
|
||||
}
|
||||
col := _plte.entries[c.data[0]];
|
||||
img.background = [3]u16{
|
||||
u16(col[0]) << 8 | u16(col[0]),
|
||||
u16(col[1]) << 8 | u16(col[1]),
|
||||
u16(col[2]) << 8 | u16(col[2]),
|
||||
};
|
||||
case 0, 4: // Grayscale, with and without Alpha
|
||||
if c.header.length != 2 {
|
||||
return {}, E_PNG.BKGD_Invalid_Length;
|
||||
}
|
||||
col := u16(mem.slice_data_cast([]u16be, c.data[:])[0]);
|
||||
img.background = [3]u16{col, col, col};
|
||||
case 2, 6: // Color, with and without Alpha
|
||||
if c.header.length != 6 {
|
||||
return {}, E_PNG.BKGD_Invalid_Length;
|
||||
}
|
||||
col := mem.slice_data_cast([]u16be, c.data[:]);
|
||||
img.background = [3]u16{u16(col[0]), u16(col[1]), u16(col[2])};
|
||||
}
|
||||
case .tRNS:
|
||||
c, err = read_chunk(ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
|
||||
if .Alpha in info.header.color_type {
|
||||
return img, E_PNG.TRNS_Encountered_Unexpectedly;
|
||||
}
|
||||
|
||||
if .return_metadata in options {
|
||||
append(&info.chunks, c);
|
||||
}
|
||||
|
||||
/*
|
||||
This makes the image one with transparency, so set it to +1 here,
|
||||
even if we need we leave img.channels alone for the defilterer's
|
||||
sake. If we early because the user just cares about metadata,
|
||||
we'll set it to 'final_image_channels'.
|
||||
*/
|
||||
|
||||
final_image_channels += 1;
|
||||
|
||||
seen_trns = true;
|
||||
if info.header.bit_depth < 8 && .Paletted not_in info.header.color_type {
|
||||
// Rescale tRNS data so key matches intensity
|
||||
dsc := depth_scale_table;
|
||||
scale := dsc[info.header.bit_depth];
|
||||
if scale != 1 {
|
||||
key := mem.slice_data_cast([]u16be, c.data)[0] * u16be(scale);
|
||||
c.data = []u8{0, u8(key & 255)};
|
||||
}
|
||||
}
|
||||
trns = c;
|
||||
case .iDOT, .CbGI:
|
||||
/*
|
||||
iPhone PNG bastardization that doesn't adhere to spec with broken IDAT chunk.
|
||||
We're not going to add support for it. If you have the misfortunte of coming
|
||||
across one of these files, use a utility to defry it.s
|
||||
*/
|
||||
return img, E_PNG.PNG_Does_Not_Adhere_to_Spec;
|
||||
case:
|
||||
// Unhandled type
|
||||
c, err = read_chunk(ctx);
|
||||
if err != nil {
|
||||
return img, err;
|
||||
}
|
||||
if .return_metadata in options {
|
||||
// NOTE: Chunk cata is currently allocated on the temp allocator.
|
||||
append(&info.chunks, c);
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
@@ -695,7 +691,7 @@ load_from_stream :: proc(stream: io.Stream, options := Options{}, allocator := c
|
||||
for p := 0; p < 7; p += 1 {
|
||||
x := (int(header.width) - ADAM7_X_ORIG[p] + ADAM7_X_SPACING[p] - 1) / ADAM7_X_SPACING[p];
|
||||
y := (int(header.height) - ADAM7_Y_ORIG[p] + ADAM7_Y_SPACING[p] - 1) / ADAM7_Y_SPACING[p];
|
||||
if (x > 0 && y > 0) {
|
||||
if x > 0 && y > 0 {
|
||||
expected_size += compute_buffer_size(int(x), int(y), int(img.channels), int(header.bit_depth), 1);
|
||||
}
|
||||
}
|
||||
@@ -854,7 +850,7 @@ load_from_stream :: proc(stream: io.Stream, options := Options{}, allocator := c
|
||||
p16 := mem.slice_data_cast([]u16, temp.buf[:]);
|
||||
o16 := mem.slice_data_cast([]u16, t.buf[:]);
|
||||
|
||||
switch (raw_image_channels) {
|
||||
switch raw_image_channels {
|
||||
case 1:
|
||||
// Gray without Alpha. Might have tRNS alpha.
|
||||
key := u16(0);
|
||||
@@ -1051,7 +1047,7 @@ load_from_stream :: proc(stream: io.Stream, options := Options{}, allocator := c
|
||||
p := mem.slice_data_cast([]u8, temp.buf[:]);
|
||||
o := mem.slice_data_cast([]u8, t.buf[:]);
|
||||
|
||||
switch (raw_image_channels) {
|
||||
switch raw_image_channels {
|
||||
case 1:
|
||||
// Gray without Alpha. Might have tRNS alpha.
|
||||
key := u8(0);
|
||||
@@ -1276,7 +1272,7 @@ defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) {
|
||||
nk := row_stride - channels;
|
||||
|
||||
filter := Row_Filter(src[0]); src = src[1:];
|
||||
switch(filter) {
|
||||
switch filter {
|
||||
case .None:
|
||||
copy(dest, src[:row_stride]);
|
||||
case .Sub:
|
||||
@@ -1590,7 +1586,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^IHDR, option
|
||||
i,j,x,y: int;
|
||||
x = (width - ADAM7_X_ORIG[p] + ADAM7_X_SPACING[p] - 1) / ADAM7_X_SPACING[p];
|
||||
y = (height - ADAM7_Y_ORIG[p] + ADAM7_Y_SPACING[p] - 1) / ADAM7_Y_SPACING[p];
|
||||
if (x > 0 && y > 0) {
|
||||
if x > 0 && y > 0 {
|
||||
temp: bytes.Buffer;
|
||||
temp_len := compute_buffer_size(x, y, channels, depth == 16 ? 16 : 8);
|
||||
resize(&temp.buf, temp_len);
|
||||
|
||||
Reference in New Issue
Block a user