Browse Source

Move `bytes` utils back to EXR code for the time being.

Also, allow PNG example to be run directly from `core:image/png` directory.
Jeroen van Rijn 4 years ago
parent
commit
ae0b8fce44
2 changed files with 24 additions and 211 deletions
  1. 0 187
      core/bytes/util.odin
  2. 24 24
      core/image/png/example.odin

+ 0 - 187
core/bytes/util.odin

@@ -1,187 +0,0 @@
-package bytes
-
-/*
-	Copyright 2021 Jeroen van Rijn <[email protected]>.
-	Made available under Odin's BSD-2 license.
-
-	List of contributors:
-		Jeroen van Rijn: Initial implementation.
-
-	`bytes.Buffer` type conversion helpers.
-*/
-
-import "core:intrinsics"
-import "core:mem"
-
-need_endian_conversion :: proc($FT: typeid, $TT: typeid) -> (res: bool) {
-
-	// true if platform endian
-	f: bool;
-	t: bool;
-
-	when ODIN_ENDIAN == "little" {
-		f = intrinsics.type_is_endian_platform(FT) || intrinsics.type_is_endian_little(FT);
-		t = intrinsics.type_is_endian_platform(TT) || intrinsics.type_is_endian_little(TT);
-
-		return f != t;
-	} else {
-		f = intrinsics.type_is_endian_platform(FT) || intrinsics.type_is_endian_big(FT);
-		t = intrinsics.type_is_endian_platform(TT) || intrinsics.type_is_endian_big(TT);
-
-		return f != t;
-	}
-
-	return;
-}
-
-/*
-	Input:
-		count:         number of elements
-		$TT:           destination type
-		$FT:           source type
-		from_buffer:   buffer to convert
-		force_convert: cast each element separately
-
-	Output:
-		res:           Converted/created buffer of []TT.
-		backing:       ^bytes.Buffer{} backing the converted data.
-		alloc:         Buffer was freshly allocated because we couldn't convert in-place. Points to `from_buffer` if `false`.
-		err:           True if we passed too few elements or allocation failed, etc.
-
-	If `from_buffer` is empty, the input type $FT is ignored and `create_buffer_of_type` is called to create a fresh buffer.
-
-	This helper will try to do as little work as possible, so if you're converting between two equally sized types,
-	and they have compatible endianness, the contents will simply be reinterpreted using `slice_data_cast`.
-
-	If you want each element to be converted in this case, set `force_convert` to `true`.
-
-	For example, converting `[]u8{0, 60}` from `[]f16` to `[]u16` will return `[15360]` when simply reinterpreted,
-	and `[1]` if force converted.
-
-	Should you for example want to promote `[]f16` to `[]f32` (or truncate `[]f32` to `[]f16`), the size of these elements
-	being different will result in a conversion anyway, so this flag is unnecessary in cases like these.
-
-	Example:
-		fmt.println("Convert []f16le (x2) to []f32 (x2).");
-		b := []u8{0, 60, 0, 60}; // == []f16{1.0, 1.0}
-
-		res, backing, had_to_allocate, err := bytes.buffer_convert_to_type(2, f32, f16le, b);
-		fmt.printf("res      : %v\n", res);              // [1.000, 1.000]
-		fmt.printf("backing  : %v\n", backing);          // &Buffer{buf = [0, 0, 128, 63, 0, 0, 128, 63], off = 0, last_read = Invalid}
-		fmt.printf("allocated: %v\n", had_to_allocate);  // true
-		fmt.printf("err      : %v\n", err);              // false
-
-		if had_to_allocate { defer bytes.buffer_destroy(backing); }
-
-		fmt.println("\nConvert []f16le (x2) to []u16 (x2).");
-
-		res2: []u16;
-		res2, backing, had_to_allocate, err = bytes.buffer_convert_to_type(2, u16, f16le, b);
-		fmt.printf("res      : %v\n", res2);             // [15360, 15360]
-		fmt.printf("backing  : %v\n", backing);          // Buffer.buf points to `b` because it could be converted in-place.
-		fmt.printf("allocated: %v\n", had_to_allocate);  // false
-		fmt.printf("err      : %v\n", err);              // false
-
-		if had_to_allocate { defer bytes.buffer_destroy(backing); }
-
-		fmt.println("\nConvert []f16le (x2) to []u16 (x2), force_convert=true.");
-
-		res2, backing, had_to_allocate, err = bytes.buffer_convert_to_type(2, u16, f16le, b, true);
-		fmt.printf("res      : %v\n", res2);             // [1, 1]
-		fmt.printf("backing  : %v\n", backing);          // Buffer.buf points to `b` because it could be converted in-place.
-		fmt.printf("allocated: %v\n", had_to_allocate);  // false
-		fmt.printf("err      : %v\n", err);              // false
-
-		if had_to_allocate { defer bytes.buffer_destroy(backing); }
-*/
-buffer_convert_to_type :: proc(count: int, $TT: typeid, $FT: typeid, from_buffer: []u8, force_convert := false) -> (
-	res: []TT, backing: ^Buffer, alloc: bool, err: bool) {
-
-	backing = new(Buffer);
-
-	if len(from_buffer) > 0 {
-		/*
-			Check if we've been given enough input elements.
-		*/
-		from := mem.slice_data_cast([]FT, from_buffer);
-		if len(from) != count {
-			err = true;
-			return;
-		}
-
-		/*
-			We can early out if the types are exactly identical.
-			This needs to be `when`, or res = from will fail if the types are different.
-		*/
-		when FT == TT {
-			res = from;
-			buffer_init(backing, from_buffer);
-			return;
-		}
-
-		/*
-			We can do a data cast if in-size == out-size and no endian conversion is needed.
-		*/
-		convert := need_endian_conversion(FT, TT);
-		convert |= (size_of(TT) * count != len(from_buffer));
-		convert |= force_convert;
-
-		if !convert {
-			// It's just a data cast
-			res = mem.slice_data_cast([]TT, from_buffer);
-			buffer_init(backing, from_buffer);
-
-			if len(res) != count {
-				err = true;
-			}
-			return;
-		} else {
-			if size_of(TT) * count == len(from_buffer) {
-				/*
-					Same size, can do an in-place Endianness conversion.
-					If `force_convert`, this also handles the per-element cast instead of slice_data_cast.
-				*/
-				res  = mem.slice_data_cast([]TT, from_buffer);
-				buffer_init(backing, from_buffer);
-				for v, i in from {
-					res[i] = TT(v);
-				}
-			} else {
-				/*
-					Result is a different size, we need to allocate an output buffer.
-				*/
-				size := size_of(TT) * count;
-				buffer_init_allocator(backing, size, size, context.allocator);
-				alloc = true;
-				res   = mem.slice_data_cast([]TT, backing.buf[:]);
-				if len(res) != count {
-					err = true;
-					return;
-				}
-
-				for v, i in from {
-					res[i] = TT(v);
-				}
-			}
-		}
-	} else {
-		/*
-			The input buffer is empty, so we'll have to create a new one for []TT of length count.
-		*/
-		res, backing, err = buffer_create_of_type(count, TT);
-		alloc = true;
-	}
-
-	return;
-}
-
-buffer_create_of_type :: proc(count: int, $TT: typeid) -> (res: []TT, backing: ^Buffer, err: bool) {
-	backing = new(Buffer);
-	size := size_of(TT) * count;
-	buffer_init_allocator(backing, size, size, context.allocator);
-	res   = mem.slice_data_cast([]TT, backing.buf[:]);
-	if len(res) != count {
-		err = true;
-	}
-	return;
-}

+ 24 - 24
core/image/png/example.odin

@@ -9,12 +9,12 @@ package png
 		Jeroen van Rijn: Initial implementation.
 		Jeroen van Rijn: Initial implementation.
 		Ginger Bill:     Cosmetic changes.
 		Ginger Bill:     Cosmetic changes.
 
 
-	An example of how to use `png.load`.
+	An example of how to use `load`.
 */
 */
 
 
 import "core:compress"
 import "core:compress"
 import "core:image"
 import "core:image"
-import "core:image/png"
+// import "core:image/png"
 import "core:bytes"
 import "core:bytes"
 import "core:fmt"
 import "core:fmt"
 
 
@@ -31,33 +31,33 @@ main :: proc() {
 
 
 	file = "../../../misc/logo-slim.png";
 	file = "../../../misc/logo-slim.png";
 
 
-	img, err = png.load(file, options);
-	defer png.destroy(img);
+	img, err = load(file, options);
+	defer destroy(img);
 
 
 	if err != nil {
 	if err != nil {
 		fmt.printf("Trying to read PNG file %v returned %v\n", file, err);
 		fmt.printf("Trying to read PNG file %v returned %v\n", file, err);
 	} else {
 	} else {
-		v: ^png.Info;
+		v: ^Info;
 
 
 		fmt.printf("Image: %vx%vx%v, %v-bit.\n", img.width, img.height, img.channels, img.depth);
 		fmt.printf("Image: %vx%vx%v, %v-bit.\n", img.width, img.height, img.channels, img.depth);
 
 
-		if img.metadata_ptr != nil && img.metadata_type == png.Info {
-			v = (^png.Info)(img.metadata_ptr);
+		if img.metadata_ptr != nil && img.metadata_type == Info {
+			v = (^Info)(img.metadata_ptr);
 			// Handle ancillary chunks as you wish.
 			// Handle ancillary chunks as you wish.
 			// We provide helper functions for a few types.
 			// We provide helper functions for a few types.
 			for c in v.chunks {
 			for c in v.chunks {
 				#partial switch c.header.type {
 				#partial switch c.header.type {
 				case .tIME:
 				case .tIME:
-					t, _ := png.core_time(c);
+					t, _ := core_time(c);
 					fmt.printf("[tIME]: %v\n", t);
 					fmt.printf("[tIME]: %v\n", t);
 				case .gAMA:
 				case .gAMA:
-					fmt.printf("[gAMA]: %v\n", png.gamma(c));
+					fmt.printf("[gAMA]: %v\n", gamma(c));
 				case .pHYs:
 				case .pHYs:
-					phys := png.phys(c);
+					phys := phys(c);
 					if phys.unit == .Meter {
 					if phys.unit == .Meter {
 						xm    := f32(img.width)  / f32(phys.ppu_x);
 						xm    := f32(img.width)  / f32(phys.ppu_x);
 						ym    := f32(img.height) / f32(phys.ppu_y);
 						ym    := f32(img.height) / f32(phys.ppu_y);
-						dpi_x, dpi_y := png.phys_to_dpi(phys);
+						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 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 resolution is %v x %v DPI.\n", dpi_x, dpi_y);
 						fmt.printf("[pHYs] Image dimensions are %v x %v meters.\n", xm, ym);
 						fmt.printf("[pHYs] Image dimensions are %v x %v meters.\n", xm, ym);
@@ -65,7 +65,7 @@ main :: proc() {
 						fmt.printf("[pHYs] x: %v, y: %v pixels per unknown unit.\n", phys.ppu_x, phys.ppu_y);
 						fmt.printf("[pHYs] x: %v, y: %v pixels per unknown unit.\n", phys.ppu_x, phys.ppu_y);
 					}
 					}
 				case .iTXt, .zTXt, .tEXt:
 				case .iTXt, .zTXt, .tEXt:
-					res, ok_text := png.text(c);
+					res, ok_text := text(c);
 					if ok_text {
 					if ok_text {
 						if c.header.type == .iTXt {
 						if c.header.type == .iTXt {
 							fmt.printf("[iTXt] %v (%v:%v): %v\n", res.keyword, res.language, res.keyword_localized, res.text);
 							fmt.printf("[iTXt] %v (%v:%v): %v\n", res.keyword, res.language, res.keyword_localized, res.text);
@@ -73,11 +73,11 @@ main :: proc() {
 							fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text);
 							fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text);
 						}
 						}
 					}
 					}
-					defer png.text_destroy(res);
+					defer text_destroy(res);
 				case .bKGD:
 				case .bKGD:
 					fmt.printf("[bKGD] %v\n", img.background);
 					fmt.printf("[bKGD] %v\n", img.background);
 				case .eXIf:
 				case .eXIf:
-					res, ok_exif := png.exif(c);
+					res, ok_exif := exif(c);
 					if ok_exif {
 					if ok_exif {
 						/*
 						/*
 							Other than checking the signature and byte order, we don't handle Exif data.
 							Other than checking the signature and byte order, we don't handle Exif data.
@@ -86,45 +86,45 @@ main :: proc() {
 						fmt.printf("[eXIf] %v\n", res);
 						fmt.printf("[eXIf] %v\n", res);
 					}
 					}
 				case .PLTE:
 				case .PLTE:
-					plte, plte_ok := png.plte(c);
+					plte, plte_ok := plte(c);
 					if plte_ok {
 					if plte_ok {
 						fmt.printf("[PLTE] %v\n", plte);
 						fmt.printf("[PLTE] %v\n", plte);
 					} else {
 					} else {
 						fmt.printf("[PLTE] Error\n");
 						fmt.printf("[PLTE] Error\n");
 					}
 					}
 				case .hIST:
 				case .hIST:
-					res, ok_hist := png.hist(c);
+					res, ok_hist := hist(c);
 					if ok_hist {
 					if ok_hist {
 						fmt.printf("[hIST] %v\n", res);
 						fmt.printf("[hIST] %v\n", res);
 					}
 					}
 				case .cHRM:
 				case .cHRM:
-					res, ok_chrm := png.chrm(c);
+					res, ok_chrm := chrm(c);
 					if ok_chrm {
 					if ok_chrm {
 						fmt.printf("[cHRM] %v\n", res);
 						fmt.printf("[cHRM] %v\n", res);
 					}
 					}
 				case .sPLT:
 				case .sPLT:
-					res, ok_splt := png.splt(c);
+					res, ok_splt := splt(c);
 					if ok_splt {
 					if ok_splt {
 						fmt.printf("[sPLT] %v\n", res);
 						fmt.printf("[sPLT] %v\n", res);
 					}
 					}
-					png.splt_destroy(res);
+					splt_destroy(res);
 				case .sBIT:
 				case .sBIT:
-					if res, ok_sbit := png.sbit(c); ok_sbit {
+					if res, ok_sbit := sbit(c); ok_sbit {
 						fmt.printf("[sBIT] %v\n", res);
 						fmt.printf("[sBIT] %v\n", res);
 					}
 					}
 				case .iCCP:
 				case .iCCP:
-					res, ok_iccp := png.iccp(c);
+					res, ok_iccp := iccp(c);
 					if ok_iccp {
 					if ok_iccp {
 						fmt.printf("[iCCP] %v\n", res);
 						fmt.printf("[iCCP] %v\n", res);
 					}
 					}
-					png.iccp_destroy(res);
+					iccp_destroy(res);
 				case .sRGB:
 				case .sRGB:
-					if res, ok_srgb := png.srgb(c); ok_srgb {
+					if res, ok_srgb := srgb(c); ok_srgb {
 						fmt.printf("[sRGB] Rendering intent: %v\n", res);
 						fmt.printf("[sRGB] Rendering intent: %v\n", res);
 					}
 					}
 				case:
 				case:
 					type := c.header.type;
 					type := c.header.type;
-					name := png.chunk_type_to_name(&type);
+					name := chunk_type_to_name(&type);
 					fmt.printf("[%v]: %v\n", name, c.data);
 					fmt.printf("[%v]: %v\n", name, c.data);
 				}
 				}
 			}
 			}