mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-31 10:22:08 +00:00
Merge branch 'master' of https://github.com/odin-lang/Odin
This commit is contained in:
@@ -1,187 +0,0 @@
|
||||
package bytes
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
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;
|
||||
}
|
||||
@@ -9,12 +9,12 @@ package png
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
Ginger Bill: Cosmetic changes.
|
||||
|
||||
An example of how to use `png.load`.
|
||||
An example of how to use `load`.
|
||||
*/
|
||||
|
||||
import "core:compress"
|
||||
import "core:image"
|
||||
import "core:image/png"
|
||||
// import "core:image/png"
|
||||
import "core:bytes"
|
||||
import "core:fmt"
|
||||
|
||||
@@ -31,33 +31,33 @@ main :: proc() {
|
||||
|
||||
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 {
|
||||
fmt.printf("Trying to read PNG file %v returned %v\n", file, err);
|
||||
} else {
|
||||
v: ^png.Info;
|
||||
v: ^Info;
|
||||
|
||||
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.
|
||||
// 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);
|
||||
t, _ := core_time(c);
|
||||
fmt.printf("[tIME]: %v\n", t);
|
||||
case .gAMA:
|
||||
fmt.printf("[gAMA]: %v\n", png.gamma(c));
|
||||
fmt.printf("[gAMA]: %v\n", gamma(c));
|
||||
case .pHYs:
|
||||
phys := png.phys(c);
|
||||
phys := 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);
|
||||
dpi_x, dpi_y := phys_to_dpi(phys);
|
||||
fmt.printf("[pHYs] Image resolution is %v x %v pixels per meter.\n", phys.ppu_x, phys.ppu_y);
|
||||
fmt.printf("[pHYs] Image resolution is %v x %v DPI.\n", dpi_x, dpi_y);
|
||||
fmt.printf("[pHYs] Image dimensions are %v x %v meters.\n", xm, ym);
|
||||
@@ -65,7 +65,7 @@ main :: proc() {
|
||||
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);
|
||||
res, ok_text := text(c);
|
||||
if ok_text {
|
||||
if c.header.type == .iTXt {
|
||||
fmt.printf("[iTXt] %v (%v:%v): %v\n", res.keyword, res.language, res.keyword_localized, res.text);
|
||||
@@ -73,11 +73,11 @@ main :: proc() {
|
||||
fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text);
|
||||
}
|
||||
}
|
||||
defer png.text_destroy(res);
|
||||
defer text_destroy(res);
|
||||
case .bKGD:
|
||||
fmt.printf("[bKGD] %v\n", img.background);
|
||||
case .eXIf:
|
||||
res, ok_exif := png.exif(c);
|
||||
res, ok_exif := exif(c);
|
||||
if ok_exif {
|
||||
/*
|
||||
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);
|
||||
}
|
||||
case .PLTE:
|
||||
plte, plte_ok := png.plte(c);
|
||||
plte, plte_ok := 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);
|
||||
res, ok_hist := hist(c);
|
||||
if ok_hist {
|
||||
fmt.printf("[hIST] %v\n", res);
|
||||
}
|
||||
case .cHRM:
|
||||
res, ok_chrm := png.chrm(c);
|
||||
res, ok_chrm := chrm(c);
|
||||
if ok_chrm {
|
||||
fmt.printf("[cHRM] %v\n", res);
|
||||
}
|
||||
case .sPLT:
|
||||
res, ok_splt := png.splt(c);
|
||||
res, ok_splt := splt(c);
|
||||
if ok_splt {
|
||||
fmt.printf("[sPLT] %v\n", res);
|
||||
}
|
||||
png.splt_destroy(res);
|
||||
splt_destroy(res);
|
||||
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);
|
||||
}
|
||||
case .iCCP:
|
||||
res, ok_iccp := png.iccp(c);
|
||||
res, ok_iccp := iccp(c);
|
||||
if ok_iccp {
|
||||
fmt.printf("[iCCP] %v\n", res);
|
||||
}
|
||||
png.iccp_destroy(res);
|
||||
iccp_destroy(res);
|
||||
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);
|
||||
}
|
||||
case:
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user