Browse Source

Minor formatting changes

gingerBill 4 years ago
parent
commit
6f745677b4
5 changed files with 362 additions and 373 deletions
  1. 6 11
      core/compress/zlib/zlib.odin
  2. 30 32
      core/image/common.odin
  3. 78 78
      core/image/png/example.odin
  4. 1 1
      core/image/png/helpers.odin
  5. 247 251
      core/image/png/png.odin

+ 6 - 11
core/compress/zlib/zlib.odin

@@ -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:

+ 30 - 32
core/image/common.odin

@@ -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);
-
-			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);
-
-			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;
+	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);
+
+		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[:]);
+
+		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
core/image/png/example.odin

@@ -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);
-						} 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("[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);
+				#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("[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);
+							fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text);
 						}
-						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);
 				}
 			}
 		}

+ 1 - 1
core/image/png/helpers.odin

@@ -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;
 

+ 247 - 251
core/image/png/png.odin

@@ -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;
-				}
-			}
-			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;
-				}
+	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;
+		}
+		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;
-
-				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;
-				}
+		case .IHDR:
+			if seen_ihdr || !first {
+				return {}, E_PNG.IHDR_Not_First_Chunk;
+			}
+			seen_ihdr = true;
 
-				if .Alpha in header.color_type {
-					img.channels += 1;
-					final_image_channels += 1;
-				}
+			header, err = read_header(ctx);
+			if err != nil {
+				return img, err;
+			}
 
-				if img.channels == 0 || img.depth == 0 {
-					return {}, E_PNG.IHDR_Corrupt;
-				}
+			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;
+			}
 
-				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;
-				}
+			if .Alpha in header.color_type {
+				img.channels += 1;
+				final_image_channels += 1;
+			}
 
-				c, err = read_chunk(&ctx);
-				if err != nil {
-					return img, err;
-				}
+			if img.channels == 0 || img.depth == 0 {
+				return {}, E_PNG.IHDR_Corrupt;
+			}
 
-				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;
-				}
+			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;
+			}
 
-				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;
-				}
+			c, err = read_chunk(ctx);
+			if err != nil {
+				return img, err;
+			}
 
-				if idat_length > 0 {
-					return img, E_PNG.IDAT_Must_Be_Contiguous;
-				}
+			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;
+			}
 
-				next := ch.type;
-				for next == .IDAT {
-					c, err = read_chunk(&ctx);
-					if err != nil {
-						return img, err;
-					}
+			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;
+			}
 
-					bytes.buffer_write(&idat_b, c.data);
-					idat_length += c.header.length;
+			if idat_length > 0 {
+				return img, E_PNG.IDAT_Must_Be_Contiguous;
+			}
 
-					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);
+			next := ch.type;
+			for next == .IDAT {
+				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
+				bytes.buffer_write(&idat_b, c.data);
+				idat_length += c.header.length;
 
-				c, err = read_chunk(&ctx);
-				if err != nil {
-					return img, err;
-				}
-				seen_bkgd = true;
-				if .return_metadata in options {
-					append(&info.chunks, c);
+				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:
 
-				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;
-				}
+			// TODO: Make sure that 16-bit bKGD + tRNS chunks return u16 instead of u16be
 
-				if .Alpha in info.header.color_type {
-					return img, E_PNG.TRNS_Encountered_Unexpectedly;
-				}
+			c, err = read_chunk(ctx);
+			if err != nil {
+				return img, err;
+			}
+			seen_bkgd = true;
+			if .return_metadata in options {
+				append(&info.chunks, c);
+			}
 
-				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;
+			}
 
-				/*
-					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 .Alpha in info.header.color_type {
+				return img, E_PNG.TRNS_Encountered_Unexpectedly;
+			}
 
-				final_image_channels += 1;
+			if .return_metadata in options {
+				append(&info.chunks, c);
+			}
 
-				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);
+			/*
+				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);