mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 22:58:46 +00:00
Remove unneeded semicolons from the core library
This commit is contained in:
+35
-35
@@ -110,7 +110,7 @@ Option :: enum {
|
||||
do_not_expand_indexed,
|
||||
do_not_expand_channels,
|
||||
}
|
||||
Options :: distinct bit_set[Option];
|
||||
Options :: distinct bit_set[Option]
|
||||
|
||||
Error :: enum {
|
||||
Invalid_PNG_Signature,
|
||||
@@ -138,8 +138,8 @@ 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;
|
||||
size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -154,61 +154,61 @@ Channel :: enum u8 {
|
||||
}
|
||||
|
||||
return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok: bool) {
|
||||
ok = false;
|
||||
t: bytes.Buffer;
|
||||
ok = false
|
||||
t: bytes.Buffer
|
||||
|
||||
idx := int(channel);
|
||||
idx := int(channel)
|
||||
|
||||
if img.channels == 2 && idx == 4 {
|
||||
// Alpha requested, which in a two channel image is index 2: G.
|
||||
idx = 2;
|
||||
idx = 2
|
||||
}
|
||||
|
||||
if idx > img.channels {
|
||||
return {}, false;
|
||||
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);
|
||||
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:];
|
||||
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);
|
||||
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:];
|
||||
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;
|
||||
return {}, false
|
||||
}
|
||||
|
||||
res = new(Image);
|
||||
res.width = img.width;
|
||||
res.height = img.height;
|
||||
res.channels = 1;
|
||||
res.depth = img.depth;
|
||||
res.pixels = t;
|
||||
res.background = img.background;
|
||||
res.metadata_ptr = img.metadata_ptr;
|
||||
res.metadata_type = img.metadata_type;
|
||||
res = new(Image)
|
||||
res.width = img.width
|
||||
res.height = img.height
|
||||
res.channels = 1
|
||||
res.depth = img.depth
|
||||
res.pixels = t
|
||||
res.background = img.background
|
||||
res.metadata_ptr = img.metadata_ptr
|
||||
res.metadata_type = img.metadata_type
|
||||
|
||||
return res, true;
|
||||
return res, true
|
||||
}
|
||||
|
||||
+156
-156
@@ -23,125 +23,125 @@ import "core:mem"
|
||||
import "core:os"
|
||||
|
||||
main :: proc() {
|
||||
track := mem.Tracking_Allocator{};
|
||||
mem.tracking_allocator_init(&track, context.allocator);
|
||||
track := mem.Tracking_Allocator{}
|
||||
mem.tracking_allocator_init(&track, context.allocator)
|
||||
|
||||
context.allocator = mem.tracking_allocator(&track);
|
||||
context.allocator = mem.tracking_allocator(&track)
|
||||
|
||||
demo();
|
||||
demo()
|
||||
|
||||
if len(track.allocation_map) > 0 {
|
||||
fmt.println("Leaks:");
|
||||
fmt.println("Leaks:")
|
||||
for _, v in track.allocation_map {
|
||||
fmt.printf("\t%v\n\n", v);
|
||||
fmt.printf("\t%v\n\n", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
demo :: proc() {
|
||||
file: string;
|
||||
file: string
|
||||
|
||||
options := image.Options{}; // {.return_metadata};
|
||||
err: compress.Error;
|
||||
img: ^image.Image;
|
||||
options := image.Options{} // {.return_metadata};
|
||||
err: compress.Error
|
||||
img: ^image.Image
|
||||
|
||||
file = "../../../misc/logo-slim.png";
|
||||
file = "../../../misc/logo-slim.png"
|
||||
|
||||
img, err = load(file, options);
|
||||
defer 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);
|
||||
fmt.printf("Trying to read PNG file %v returned %v\n", file, err)
|
||||
} else {
|
||||
v: ^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 == Info {
|
||||
v = (^Info)(img.metadata_ptr);
|
||||
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, _ := core_time(c);
|
||||
fmt.printf("[tIME]: %v\n", t);
|
||||
t, _ := core_time(c)
|
||||
fmt.printf("[tIME]: %v\n", t)
|
||||
case .gAMA:
|
||||
fmt.printf("[gAMA]: %v\n", gamma(c));
|
||||
fmt.printf("[gAMA]: %v\n", gamma(c))
|
||||
case .pHYs:
|
||||
phys := 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 := 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);
|
||||
xm := f32(img.width) / f32(phys.ppu_x)
|
||||
ym := f32(img.height) / f32(phys.ppu_y)
|
||||
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)
|
||||
} else {
|
||||
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:
|
||||
res, ok_text := 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);
|
||||
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);
|
||||
fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text)
|
||||
}
|
||||
}
|
||||
defer text_destroy(res);
|
||||
defer text_destroy(res)
|
||||
case .bKGD:
|
||||
fmt.printf("[bKGD] %v\n", img.background);
|
||||
fmt.printf("[bKGD] %v\n", img.background)
|
||||
case .eXIf:
|
||||
res, ok_exif := exif(c);
|
||||
res, ok_exif := 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);
|
||||
fmt.printf("[eXIf] %v\n", res)
|
||||
}
|
||||
case .PLTE:
|
||||
plte, plte_ok := plte(c);
|
||||
plte, plte_ok := plte(c)
|
||||
if plte_ok {
|
||||
fmt.printf("[PLTE] %v\n", plte);
|
||||
fmt.printf("[PLTE] %v\n", plte)
|
||||
} else {
|
||||
fmt.printf("[PLTE] Error\n");
|
||||
fmt.printf("[PLTE] Error\n")
|
||||
}
|
||||
case .hIST:
|
||||
res, ok_hist := hist(c);
|
||||
res, ok_hist := hist(c)
|
||||
if ok_hist {
|
||||
fmt.printf("[hIST] %v\n", res);
|
||||
fmt.printf("[hIST] %v\n", res)
|
||||
}
|
||||
case .cHRM:
|
||||
res, ok_chrm := chrm(c);
|
||||
res, ok_chrm := chrm(c)
|
||||
if ok_chrm {
|
||||
fmt.printf("[cHRM] %v\n", res);
|
||||
fmt.printf("[cHRM] %v\n", res)
|
||||
}
|
||||
case .sPLT:
|
||||
res, ok_splt := splt(c);
|
||||
res, ok_splt := splt(c)
|
||||
if ok_splt {
|
||||
fmt.printf("[sPLT] %v\n", res);
|
||||
fmt.printf("[sPLT] %v\n", res)
|
||||
}
|
||||
splt_destroy(res);
|
||||
splt_destroy(res)
|
||||
case .sBIT:
|
||||
if res, ok_sbit := sbit(c); ok_sbit {
|
||||
fmt.printf("[sBIT] %v\n", res);
|
||||
fmt.printf("[sBIT] %v\n", res)
|
||||
}
|
||||
case .iCCP:
|
||||
res, ok_iccp := iccp(c);
|
||||
res, ok_iccp := iccp(c)
|
||||
if ok_iccp {
|
||||
fmt.printf("[iCCP] %v\n", res);
|
||||
fmt.printf("[iCCP] %v\n", res)
|
||||
}
|
||||
iccp_destroy(res);
|
||||
iccp_destroy(res)
|
||||
case .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:
|
||||
type := c.header.type;
|
||||
name := chunk_type_to_name(&type);
|
||||
fmt.printf("[%v]: %v\n", name, c.data);
|
||||
type := c.header.type
|
||||
name := chunk_type_to_name(&type)
|
||||
fmt.printf("[%v]: %v\n", name, c.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,10 +149,10 @@ demo :: proc() {
|
||||
|
||||
if err == nil && .do_not_decompress_image not_in options && .info not_in options {
|
||||
if ok := write_image_as_ppm("out.ppm", img); ok {
|
||||
fmt.println("Saved decoded image.");
|
||||
fmt.println("Saved decoded image.")
|
||||
} else {
|
||||
fmt.println("Error saving out.ppm.");
|
||||
fmt.println(img);
|
||||
fmt.println("Error saving out.ppm.")
|
||||
fmt.println(img)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,193 +162,193 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b
|
||||
|
||||
_bg :: proc(bg: Maybe([3]u16), x, y: int, high := true) -> (res: [3]u16) {
|
||||
if v, ok := bg.?; ok {
|
||||
res = v;
|
||||
res = v
|
||||
} else {
|
||||
if high {
|
||||
l := u16(30 * 256 + 30);
|
||||
l := u16(30 * 256 + 30)
|
||||
|
||||
if (x & 4 == 0) ~ (y & 4 == 0) {
|
||||
res = [3]u16{l, 0, l};
|
||||
res = [3]u16{l, 0, l}
|
||||
} else {
|
||||
res = [3]u16{l >> 1, 0, l >> 1};
|
||||
res = [3]u16{l >> 1, 0, l >> 1}
|
||||
}
|
||||
} else {
|
||||
if (x & 4 == 0) ~ (y & 4 == 0) {
|
||||
res = [3]u16{30, 30, 30};
|
||||
res = [3]u16{30, 30, 30}
|
||||
} else {
|
||||
res = [3]u16{15, 15, 15};
|
||||
res = [3]u16{15, 15, 15}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// profiler.timed_proc();
|
||||
using image;
|
||||
using os;
|
||||
using image
|
||||
using os
|
||||
|
||||
flags: int = O_WRONLY|O_CREATE|O_TRUNC;
|
||||
flags: int = O_WRONLY|O_CREATE|O_TRUNC
|
||||
|
||||
img := image;
|
||||
img := image
|
||||
|
||||
// PBM 16-bit images are big endian
|
||||
when ODIN_ENDIAN == "little" {
|
||||
if img.depth == 16 {
|
||||
// The pixel components are in Big Endian. Let's byteswap back.
|
||||
input := mem.slice_data_cast([]u16, img.pixels.buf[:]);
|
||||
output := mem.slice_data_cast([]u16be, img.pixels.buf[:]);
|
||||
input := mem.slice_data_cast([]u16, img.pixels.buf[:])
|
||||
output := mem.slice_data_cast([]u16be, img.pixels.buf[:])
|
||||
#no_bounds_check for v, i in input {
|
||||
output[i] = u16be(v);
|
||||
output[i] = u16be(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pix := bytes.buffer_to_bytes(&img.pixels);
|
||||
pix := bytes.buffer_to_bytes(&img.pixels)
|
||||
|
||||
if len(pix) == 0 || len(pix) < image.width * image.height * int(image.channels) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
mode: int = 0;
|
||||
mode: int = 0
|
||||
when ODIN_OS == "linux" || ODIN_OS == "darwin" {
|
||||
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||
}
|
||||
|
||||
fd, err := open(filename, flags, mode);
|
||||
fd, err := open(filename, flags, mode)
|
||||
if err != 0 {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
defer close(fd);
|
||||
defer close(fd)
|
||||
|
||||
write_string(fd,
|
||||
fmt.tprintf("P6\n%v %v\n%v\n", width, height, (1 << uint(depth) - 1)),
|
||||
);
|
||||
)
|
||||
|
||||
if channels == 3 {
|
||||
// We don't handle transparency here...
|
||||
write_ptr(fd, raw_data(pix), len(pix));
|
||||
write_ptr(fd, raw_data(pix), len(pix))
|
||||
} else {
|
||||
bpp := depth == 16 ? 2 : 1;
|
||||
bytes_needed := width * height * 3 * bpp;
|
||||
bpp := depth == 16 ? 2 : 1
|
||||
bytes_needed := width * height * 3 * bpp
|
||||
|
||||
op := bytes.Buffer{};
|
||||
bytes.buffer_init_allocator(&op, bytes_needed, bytes_needed);
|
||||
defer bytes.buffer_destroy(&op);
|
||||
op := bytes.Buffer{}
|
||||
bytes.buffer_init_allocator(&op, bytes_needed, bytes_needed)
|
||||
defer bytes.buffer_destroy(&op)
|
||||
|
||||
if channels == 1 {
|
||||
if depth == 16 {
|
||||
assert(len(pix) == width * height * 2);
|
||||
p16 := mem.slice_data_cast([]u16, pix);
|
||||
o16 := mem.slice_data_cast([]u16, op.buf[:]);
|
||||
assert(len(pix) == width * height * 2)
|
||||
p16 := mem.slice_data_cast([]u16, pix)
|
||||
o16 := mem.slice_data_cast([]u16, op.buf[:])
|
||||
#no_bounds_check for len(p16) != 0 {
|
||||
r := u16(p16[0]);
|
||||
o16[0] = r;
|
||||
o16[1] = r;
|
||||
o16[2] = r;
|
||||
p16 = p16[1:];
|
||||
o16 = o16[3:];
|
||||
r := u16(p16[0])
|
||||
o16[0] = r
|
||||
o16[1] = r
|
||||
o16[2] = r
|
||||
p16 = p16[1:]
|
||||
o16 = o16[3:]
|
||||
}
|
||||
} else {
|
||||
o := 0;
|
||||
o := 0
|
||||
for i := 0; i < len(pix); i += 1 {
|
||||
r := pix[i];
|
||||
op.buf[o ] = r;
|
||||
op.buf[o+1] = r;
|
||||
op.buf[o+2] = r;
|
||||
o += 3;
|
||||
r := pix[i]
|
||||
op.buf[o ] = r
|
||||
op.buf[o+1] = r
|
||||
op.buf[o+2] = r
|
||||
o += 3
|
||||
}
|
||||
}
|
||||
write_ptr(fd, raw_data(op.buf), len(op.buf));
|
||||
write_ptr(fd, raw_data(op.buf), len(op.buf))
|
||||
} else if channels == 2 {
|
||||
if depth == 16 {
|
||||
p16 := mem.slice_data_cast([]u16, pix);
|
||||
o16 := mem.slice_data_cast([]u16, op.buf[:]);
|
||||
p16 := mem.slice_data_cast([]u16, pix)
|
||||
o16 := mem.slice_data_cast([]u16, op.buf[:])
|
||||
|
||||
bgcol := img.background;
|
||||
bgcol := img.background
|
||||
|
||||
#no_bounds_check for len(p16) != 0 {
|
||||
r := f64(u16(p16[0]));
|
||||
bg: f64;
|
||||
r := f64(u16(p16[0]))
|
||||
bg: f64
|
||||
if bgcol != nil {
|
||||
v := bgcol.([3]u16)[0];
|
||||
bg = f64(v);
|
||||
v := bgcol.([3]u16)[0]
|
||||
bg = f64(v)
|
||||
}
|
||||
a := f64(u16(p16[1])) / 65535.0;
|
||||
l := (a * r) + (1 - a) * bg;
|
||||
a := f64(u16(p16[1])) / 65535.0
|
||||
l := (a * r) + (1 - a) * bg
|
||||
|
||||
o16[0] = u16(l);
|
||||
o16[1] = u16(l);
|
||||
o16[2] = u16(l);
|
||||
o16[0] = u16(l)
|
||||
o16[1] = u16(l)
|
||||
o16[2] = u16(l)
|
||||
|
||||
p16 = p16[2:];
|
||||
o16 = o16[3:];
|
||||
p16 = p16[2:]
|
||||
o16 = o16[3:]
|
||||
}
|
||||
} else {
|
||||
o := 0;
|
||||
o := 0
|
||||
for i := 0; i < len(pix); i += 2 {
|
||||
r := pix[i]; a := pix[i+1]; a1 := f32(a) / 255.0;
|
||||
c := u8(f32(r) * a1);
|
||||
op.buf[o ] = c;
|
||||
op.buf[o+1] = c;
|
||||
op.buf[o+2] = c;
|
||||
o += 3;
|
||||
r := pix[i]; a := pix[i+1]; a1 := f32(a) / 255.0
|
||||
c := u8(f32(r) * a1)
|
||||
op.buf[o ] = c
|
||||
op.buf[o+1] = c
|
||||
op.buf[o+2] = c
|
||||
o += 3
|
||||
}
|
||||
}
|
||||
write_ptr(fd, raw_data(op.buf), len(op.buf));
|
||||
write_ptr(fd, raw_data(op.buf), len(op.buf))
|
||||
} else if channels == 4 {
|
||||
if depth == 16 {
|
||||
p16 := mem.slice_data_cast([]u16be, pix);
|
||||
o16 := mem.slice_data_cast([]u16be, op.buf[:]);
|
||||
p16 := mem.slice_data_cast([]u16be, pix)
|
||||
o16 := mem.slice_data_cast([]u16be, op.buf[:])
|
||||
|
||||
#no_bounds_check for len(p16) != 0 {
|
||||
|
||||
bg := _bg(img.background, 0, 0);
|
||||
r := f32(p16[0]);
|
||||
g := f32(p16[1]);
|
||||
b := f32(p16[2]);
|
||||
a := f32(p16[3]) / 65535.0;
|
||||
bg := _bg(img.background, 0, 0)
|
||||
r := f32(p16[0])
|
||||
g := f32(p16[1])
|
||||
b := f32(p16[2])
|
||||
a := f32(p16[3]) / 65535.0
|
||||
|
||||
lr := (a * r) + (1 - a) * f32(bg[0]);
|
||||
lg := (a * g) + (1 - a) * f32(bg[1]);
|
||||
lb := (a * b) + (1 - a) * f32(bg[2]);
|
||||
lr := (a * r) + (1 - a) * f32(bg[0])
|
||||
lg := (a * g) + (1 - a) * f32(bg[1])
|
||||
lb := (a * b) + (1 - a) * f32(bg[2])
|
||||
|
||||
o16[0] = u16be(lr);
|
||||
o16[1] = u16be(lg);
|
||||
o16[2] = u16be(lb);
|
||||
o16[0] = u16be(lr)
|
||||
o16[1] = u16be(lg)
|
||||
o16[2] = u16be(lb)
|
||||
|
||||
p16 = p16[4:];
|
||||
o16 = o16[3:];
|
||||
p16 = p16[4:]
|
||||
o16 = o16[3:]
|
||||
}
|
||||
} else {
|
||||
o := 0;
|
||||
o := 0
|
||||
|
||||
for i := 0; i < len(pix); i += 4 {
|
||||
|
||||
x := (i / 4) % width;
|
||||
y := i / width / 4;
|
||||
x := (i / 4) % width
|
||||
y := i / width / 4
|
||||
|
||||
_b := _bg(img.background, x, y, false);
|
||||
bgcol := [3]u8{u8(_b[0]), u8(_b[1]), u8(_b[2])};
|
||||
_b := _bg(img.background, x, y, false)
|
||||
bgcol := [3]u8{u8(_b[0]), u8(_b[1]), u8(_b[2])}
|
||||
|
||||
r := f32(pix[i]);
|
||||
g := f32(pix[i+1]);
|
||||
b := f32(pix[i+2]);
|
||||
a := f32(pix[i+3]) / 255.0;
|
||||
r := f32(pix[i])
|
||||
g := f32(pix[i+1])
|
||||
b := f32(pix[i+2])
|
||||
a := f32(pix[i+3]) / 255.0
|
||||
|
||||
lr := u8(f32(r) * a + (1 - a) * f32(bgcol[0]));
|
||||
lg := u8(f32(g) * a + (1 - a) * f32(bgcol[1]));
|
||||
lb := u8(f32(b) * a + (1 - a) * f32(bgcol[2]));
|
||||
op.buf[o ] = lr;
|
||||
op.buf[o+1] = lg;
|
||||
op.buf[o+2] = lb;
|
||||
o += 3;
|
||||
lr := u8(f32(r) * a + (1 - a) * f32(bgcol[0]))
|
||||
lg := u8(f32(g) * a + (1 - a) * f32(bgcol[1]))
|
||||
lb := u8(f32(b) * a + (1 - a) * f32(bgcol[2]))
|
||||
op.buf[o ] = lr
|
||||
op.buf[o+1] = lg
|
||||
op.buf[o+2] = lb
|
||||
o += 3
|
||||
}
|
||||
}
|
||||
write_ptr(fd, raw_data(op.buf), len(op.buf));
|
||||
write_ptr(fd, raw_data(op.buf), len(op.buf))
|
||||
} else {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
+200
-200
@@ -30,12 +30,12 @@ destroy :: proc(img: ^Image) {
|
||||
Nothing to do.
|
||||
Load must've returned with an error.
|
||||
*/
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
bytes.buffer_destroy(&img.pixels);
|
||||
bytes.buffer_destroy(&img.pixels)
|
||||
// Clean up Info.
|
||||
free(img.metadata_ptr);
|
||||
free(img.metadata_ptr)
|
||||
|
||||
/*
|
||||
We don't need to do anything for the individual chunks.
|
||||
@@ -43,7 +43,7 @@ destroy :: proc(img: ^Image) {
|
||||
|
||||
See read_chunk.
|
||||
*/
|
||||
free(img);
|
||||
free(img)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -51,259 +51,259 @@ destroy :: proc(img: ^Image) {
|
||||
*/
|
||||
|
||||
gamma :: proc(c: Chunk) -> f32 {
|
||||
assert(c.header.type == .gAMA);
|
||||
res := (^gAMA)(raw_data(c.data))^;
|
||||
assert(c.header.type == .gAMA)
|
||||
res := (^gAMA)(raw_data(c.data))^
|
||||
when true {
|
||||
// Returns the wrong result on old backend
|
||||
// Fixed for -llvm-api
|
||||
return f32(res.gamma_100k) / 100_000.0;
|
||||
return f32(res.gamma_100k) / 100_000.0
|
||||
} else {
|
||||
return f32(u32(res.gamma_100k)) / 100_000.0;
|
||||
return f32(u32(res.gamma_100k)) / 100_000.0
|
||||
}
|
||||
}
|
||||
|
||||
INCHES_PER_METER :: 1000.0 / 25.4;
|
||||
INCHES_PER_METER :: 1000.0 / 25.4
|
||||
|
||||
phys :: proc(c: Chunk) -> pHYs {
|
||||
assert(c.header.type == .pHYs);
|
||||
res := (^pHYs)(raw_data(c.data))^;
|
||||
return res;
|
||||
assert(c.header.type == .pHYs)
|
||||
res := (^pHYs)(raw_data(c.data))^
|
||||
return res
|
||||
}
|
||||
|
||||
phys_to_dpi :: proc(p: pHYs) -> (x_dpi, y_dpi: f32) {
|
||||
return f32(p.ppu_x) / INCHES_PER_METER, f32(p.ppu_y) / INCHES_PER_METER;
|
||||
return f32(p.ppu_x) / INCHES_PER_METER, f32(p.ppu_y) / INCHES_PER_METER
|
||||
}
|
||||
|
||||
time :: proc(c: Chunk) -> tIME {
|
||||
assert(c.header.type == .tIME);
|
||||
res := (^tIME)(raw_data(c.data))^;
|
||||
return res;
|
||||
assert(c.header.type == .tIME)
|
||||
res := (^tIME)(raw_data(c.data))^
|
||||
return res
|
||||
}
|
||||
|
||||
core_time :: proc(c: Chunk) -> (t: coretime.Time, ok: bool) {
|
||||
png_time := time(c);
|
||||
using png_time;
|
||||
png_time := time(c)
|
||||
using png_time
|
||||
return coretime.datetime_to_time(
|
||||
int(year), int(month), int(day),
|
||||
int(hour), int(minute), int(second),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
text :: proc(c: Chunk) -> (res: Text, ok: bool) {
|
||||
#partial switch c.header.type {
|
||||
case .tEXt:
|
||||
ok = true;
|
||||
ok = true
|
||||
|
||||
fields := bytes.split(s=c.data, sep=[]u8{0}, allocator=context.temp_allocator);
|
||||
fields := bytes.split(s=c.data, sep=[]u8{0}, allocator=context.temp_allocator)
|
||||
if len(fields) == 2 {
|
||||
res.keyword = strings.clone(string(fields[0]));
|
||||
res.text = strings.clone(string(fields[1]));
|
||||
res.keyword = strings.clone(string(fields[0]))
|
||||
res.text = strings.clone(string(fields[1]))
|
||||
} else {
|
||||
ok = false;
|
||||
ok = false
|
||||
}
|
||||
return;
|
||||
return
|
||||
case .zTXt:
|
||||
ok = true;
|
||||
ok = true
|
||||
|
||||
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator);
|
||||
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator)
|
||||
if len(fields) != 3 || len(fields[1]) != 0 {
|
||||
// Compression method must be 0=Deflate, which thanks to the split above turns
|
||||
// into an empty slice
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
|
||||
// Set up ZLIB context and decompress text payload.
|
||||
buf: bytes.Buffer;
|
||||
zlib_error := zlib.inflate_from_byte_array(fields[2], &buf);
|
||||
defer bytes.buffer_destroy(&buf);
|
||||
buf: bytes.Buffer
|
||||
zlib_error := zlib.inflate_from_byte_array(fields[2], &buf)
|
||||
defer bytes.buffer_destroy(&buf)
|
||||
if zlib_error != nil {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
|
||||
res.keyword = strings.clone(string(fields[0]));
|
||||
res.text = strings.clone(bytes.buffer_to_string(&buf));
|
||||
return;
|
||||
res.keyword = strings.clone(string(fields[0]))
|
||||
res.text = strings.clone(bytes.buffer_to_string(&buf))
|
||||
return
|
||||
case .iTXt:
|
||||
ok = true;
|
||||
ok = true
|
||||
|
||||
s := string(c.data);
|
||||
null := strings.index_byte(s, 0);
|
||||
s := string(c.data)
|
||||
null := strings.index_byte(s, 0)
|
||||
if null == -1 {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
if len(c.data) < null + 4 {
|
||||
// At a minimum, including the \0 following the keyword, we require 5 more bytes.
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
res.keyword = strings.clone(string(c.data[:null]));
|
||||
rest := c.data[null+1:];
|
||||
res.keyword = strings.clone(string(c.data[:null]))
|
||||
rest := c.data[null+1:]
|
||||
|
||||
compression_flag := rest[:1][0];
|
||||
compression_flag := rest[:1][0]
|
||||
if compression_flag > 1 {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
compression_method := rest[1:2][0];
|
||||
compression_method := rest[1:2][0]
|
||||
if compression_flag == 1 && compression_method > 0 {
|
||||
// Only Deflate is supported
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
rest = rest[2:];
|
||||
rest = rest[2:]
|
||||
|
||||
// We now expect an optional language keyword and translated keyword, both followed by a \0
|
||||
null = strings.index_byte(string(rest), 0);
|
||||
null = strings.index_byte(string(rest), 0)
|
||||
if null == -1 {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
res.language = strings.clone(string(rest[:null]));
|
||||
rest = rest[null+1:];
|
||||
res.language = strings.clone(string(rest[:null]))
|
||||
rest = rest[null+1:]
|
||||
|
||||
null = strings.index_byte(string(rest), 0);
|
||||
null = strings.index_byte(string(rest), 0)
|
||||
if null == -1 {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
res.keyword_localized = strings.clone(string(rest[:null]));
|
||||
rest = rest[null+1:];
|
||||
res.keyword_localized = strings.clone(string(rest[:null]))
|
||||
rest = rest[null+1:]
|
||||
if compression_flag == 0 {
|
||||
res.text = strings.clone(string(rest));
|
||||
res.text = strings.clone(string(rest))
|
||||
} else {
|
||||
// Set up ZLIB context and decompress text payload.
|
||||
buf: bytes.Buffer;
|
||||
zlib_error := zlib.inflate_from_byte_array(rest, &buf);
|
||||
defer bytes.buffer_destroy(&buf);
|
||||
buf: bytes.Buffer
|
||||
zlib_error := zlib.inflate_from_byte_array(rest, &buf)
|
||||
defer bytes.buffer_destroy(&buf)
|
||||
if zlib_error != nil {
|
||||
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
|
||||
res.text = strings.clone(bytes.buffer_to_string(&buf));
|
||||
res.text = strings.clone(bytes.buffer_to_string(&buf))
|
||||
}
|
||||
return;
|
||||
return
|
||||
case:
|
||||
// PNG text helper called with an unrecognized chunk type.
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
}
|
||||
|
||||
text_destroy :: proc(text: Text) {
|
||||
delete(text.keyword);
|
||||
delete(text.keyword_localized);
|
||||
delete(text.language);
|
||||
delete(text.text);
|
||||
delete(text.keyword)
|
||||
delete(text.keyword_localized)
|
||||
delete(text.language)
|
||||
delete(text.text)
|
||||
}
|
||||
|
||||
iccp :: proc(c: Chunk) -> (res: iCCP, ok: bool) {
|
||||
ok = true;
|
||||
ok = true
|
||||
|
||||
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator);
|
||||
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator)
|
||||
|
||||
if len(fields[0]) < 1 || len(fields[0]) > 79 {
|
||||
// Invalid profile name
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
|
||||
if len(fields[1]) != 0 {
|
||||
// Compression method should be a zero, which the split turned into an empty slice.
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
|
||||
// Set up ZLIB context and decompress iCCP payload
|
||||
buf: bytes.Buffer;
|
||||
zlib_error := zlib.inflate_from_byte_array(fields[2], &buf);
|
||||
buf: bytes.Buffer
|
||||
zlib_error := zlib.inflate_from_byte_array(fields[2], &buf)
|
||||
if zlib_error != nil {
|
||||
bytes.buffer_destroy(&buf);
|
||||
ok = false; return;
|
||||
bytes.buffer_destroy(&buf)
|
||||
ok = false; return
|
||||
}
|
||||
|
||||
res.name = strings.clone(string(fields[0]));
|
||||
res.profile = bytes.buffer_to_bytes(&buf);
|
||||
res.name = strings.clone(string(fields[0]))
|
||||
res.profile = bytes.buffer_to_bytes(&buf)
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
iccp_destroy :: proc(i: iCCP) {
|
||||
delete(i.name);
|
||||
delete(i.name)
|
||||
|
||||
delete(i.profile);
|
||||
delete(i.profile)
|
||||
|
||||
}
|
||||
|
||||
srgb :: proc(c: Chunk) -> (res: sRGB, ok: bool) {
|
||||
ok = true;
|
||||
ok = true
|
||||
|
||||
if c.header.type != .sRGB || len(c.data) != 1 {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
|
||||
res.intent = sRGB_Rendering_Intent(c.data[0]);
|
||||
res.intent = sRGB_Rendering_Intent(c.data[0])
|
||||
if res.intent > max(sRGB_Rendering_Intent) {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
plte :: proc(c: Chunk) -> (res: PLTE, ok: bool) {
|
||||
if c.header.type != .PLTE {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
|
||||
i := 0; j := 0; ok = true;
|
||||
i := 0; j := 0; ok = true
|
||||
for j < int(c.header.length) {
|
||||
res.entries[i] = {c.data[j], c.data[j+1], c.data[j+2]};
|
||||
i += 1; j += 3;
|
||||
res.entries[i] = {c.data[j], c.data[j+1], c.data[j+2]}
|
||||
i += 1; j += 3
|
||||
}
|
||||
res.used = u16(i);
|
||||
return;
|
||||
res.used = u16(i)
|
||||
return
|
||||
}
|
||||
|
||||
splt :: proc(c: Chunk) -> (res: sPLT, ok: bool) {
|
||||
if c.header.type != .sPLT {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
ok = true;
|
||||
ok = true
|
||||
|
||||
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=2, allocator=context.temp_allocator);
|
||||
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=2, allocator=context.temp_allocator)
|
||||
if len(fields) != 2 {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
|
||||
res.depth = fields[1][0];
|
||||
res.depth = fields[1][0]
|
||||
if res.depth != 8 && res.depth != 16 {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
|
||||
data := fields[1][1:];
|
||||
count: int;
|
||||
data := fields[1][1:]
|
||||
count: int
|
||||
|
||||
if res.depth == 8 {
|
||||
if len(data) % 6 != 0 {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
count = len(data) / 6;
|
||||
count = len(data) / 6
|
||||
if count > 256 {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
|
||||
res.entries = mem.slice_data_cast([][4]u8, data);
|
||||
res.entries = mem.slice_data_cast([][4]u8, data)
|
||||
} else { // res.depth == 16
|
||||
if len(data) % 10 != 0 {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
count = len(data) / 10;
|
||||
count = len(data) / 10
|
||||
if count > 256 {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
|
||||
res.entries = mem.slice_data_cast([][4]u16, data);
|
||||
res.entries = mem.slice_data_cast([][4]u16, data)
|
||||
}
|
||||
|
||||
res.name = strings.clone(string(fields[0]));
|
||||
res.used = u16(count);
|
||||
res.name = strings.clone(string(fields[0]))
|
||||
res.used = u16(count)
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
splt_destroy :: proc(s: sPLT) {
|
||||
delete(s.name);
|
||||
delete(s.name)
|
||||
}
|
||||
|
||||
sbit :: proc(c: Chunk) -> (res: [4]u8, ok: bool) {
|
||||
@@ -313,88 +313,88 @@ sbit :: proc(c: Chunk) -> (res: [4]u8, ok: bool) {
|
||||
*/
|
||||
|
||||
if len(c.data) < 1 || len(c.data) > 4 {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
ok = true;
|
||||
ok = true
|
||||
|
||||
for i := 0; i < len(c.data); i += 1 {
|
||||
res[i] = c.data[i];
|
||||
res[i] = c.data[i]
|
||||
}
|
||||
return;
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
hist :: proc(c: Chunk) -> (res: hIST, ok: bool) {
|
||||
if c.header.type != .hIST {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
if c.header.length & 1 == 1 || c.header.length > 512 {
|
||||
// The entries are u16be, so the length must be even.
|
||||
// At most 256 entries must be present
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
|
||||
ok = true;
|
||||
data := mem.slice_data_cast([]u16be, c.data);
|
||||
i := 0;
|
||||
ok = true
|
||||
data := mem.slice_data_cast([]u16be, c.data)
|
||||
i := 0
|
||||
for len(data) > 0 {
|
||||
// HIST entries are u16be, we unpack them to machine format
|
||||
res.entries[i] = u16(data[0]);
|
||||
i += 1; data = data[1:];
|
||||
res.entries[i] = u16(data[0])
|
||||
i += 1; data = data[1:]
|
||||
}
|
||||
res.used = u16(i);
|
||||
return;
|
||||
res.used = u16(i)
|
||||
return
|
||||
}
|
||||
|
||||
chrm :: proc(c: Chunk) -> (res: cHRM, ok: bool) {
|
||||
ok = true;
|
||||
ok = true
|
||||
if c.header.length != size_of(cHRM_Raw) {
|
||||
return {}, false;
|
||||
return {}, false
|
||||
}
|
||||
chrm := (^cHRM_Raw)(raw_data(c.data))^;
|
||||
chrm := (^cHRM_Raw)(raw_data(c.data))^
|
||||
|
||||
res.w.x = f32(chrm.w.x) / 100_000.0;
|
||||
res.w.y = f32(chrm.w.y) / 100_000.0;
|
||||
res.r.x = f32(chrm.r.x) / 100_000.0;
|
||||
res.r.y = f32(chrm.r.y) / 100_000.0;
|
||||
res.g.x = f32(chrm.g.x) / 100_000.0;
|
||||
res.g.y = f32(chrm.g.y) / 100_000.0;
|
||||
res.b.x = f32(chrm.b.x) / 100_000.0;
|
||||
res.b.y = f32(chrm.b.y) / 100_000.0;
|
||||
return;
|
||||
res.w.x = f32(chrm.w.x) / 100_000.0
|
||||
res.w.y = f32(chrm.w.y) / 100_000.0
|
||||
res.r.x = f32(chrm.r.x) / 100_000.0
|
||||
res.r.y = f32(chrm.r.y) / 100_000.0
|
||||
res.g.x = f32(chrm.g.x) / 100_000.0
|
||||
res.g.y = f32(chrm.g.y) / 100_000.0
|
||||
res.b.x = f32(chrm.b.x) / 100_000.0
|
||||
res.b.y = f32(chrm.b.y) / 100_000.0
|
||||
return
|
||||
}
|
||||
|
||||
exif :: proc(c: Chunk) -> (res: Exif, ok: bool) {
|
||||
|
||||
ok = true;
|
||||
ok = true
|
||||
|
||||
if len(c.data) < 4 {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
|
||||
if c.data[0] == 'M' && c.data[1] == 'M' {
|
||||
res.byte_order = .big_endian;
|
||||
res.byte_order = .big_endian
|
||||
if c.data[2] != 0 || c.data[3] != 42 {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
} else if c.data[0] == 'I' && c.data[1] == 'I' {
|
||||
res.byte_order = .little_endian;
|
||||
res.byte_order = .little_endian
|
||||
if c.data[2] != 42 || c.data[3] != 0 {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
} else {
|
||||
ok = false; return;
|
||||
ok = false; return
|
||||
}
|
||||
|
||||
res.data = c.data;
|
||||
return;
|
||||
res.data = c.data
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
General helper functions
|
||||
*/
|
||||
|
||||
compute_buffer_size :: image.compute_buffer_size;
|
||||
compute_buffer_size :: image.compute_buffer_size
|
||||
|
||||
/*
|
||||
PNG save helpers
|
||||
@@ -404,59 +404,59 @@ when false {
|
||||
|
||||
make_chunk :: proc(c: any, t: Chunk_Type) -> (res: Chunk) {
|
||||
|
||||
data: []u8;
|
||||
data: []u8
|
||||
if v, ok := c.([]u8); ok {
|
||||
data = v;
|
||||
data = v
|
||||
} else {
|
||||
data = mem.any_to_bytes(c);
|
||||
data = mem.any_to_bytes(c)
|
||||
}
|
||||
|
||||
res.header.length = u32be(len(data));
|
||||
res.header.type = t;
|
||||
res.data = data;
|
||||
res.header.length = u32be(len(data))
|
||||
res.header.type = t
|
||||
res.data = data
|
||||
|
||||
// CRC the type
|
||||
crc := hash.crc32(mem.any_to_bytes(res.header.type));
|
||||
crc := hash.crc32(mem.any_to_bytes(res.header.type))
|
||||
// Extend the CRC with the data
|
||||
res.crc = u32be(hash.crc32(data, crc));
|
||||
return;
|
||||
res.crc = u32be(hash.crc32(data, crc))
|
||||
return
|
||||
}
|
||||
|
||||
write_chunk :: proc(fd: os.Handle, chunk: Chunk) {
|
||||
c := chunk;
|
||||
c := chunk
|
||||
// Write length + type
|
||||
os.write_ptr(fd, &c.header, 8);
|
||||
os.write_ptr(fd, &c.header, 8)
|
||||
// Write data
|
||||
os.write_ptr(fd, mem.raw_data(c.data), int(c.header.length));
|
||||
os.write_ptr(fd, mem.raw_data(c.data), int(c.header.length))
|
||||
// Write CRC32
|
||||
os.write_ptr(fd, &c.crc, 4);
|
||||
os.write_ptr(fd, &c.crc, 4)
|
||||
}
|
||||
|
||||
write_image_as_png :: proc(filename: string, image: Image) -> (err: Error) {
|
||||
profiler.timed_proc();
|
||||
using image;
|
||||
using os;
|
||||
flags: int = O_WRONLY|O_CREATE|O_TRUNC;
|
||||
profiler.timed_proc()
|
||||
using image
|
||||
using os
|
||||
flags: int = O_WRONLY|O_CREATE|O_TRUNC
|
||||
|
||||
if len(image.pixels) == 0 || len(image.pixels) < image.width * image.height * int(image.channels) {
|
||||
return E_PNG.Invalid_Image_Dimensions;
|
||||
return E_PNG.Invalid_Image_Dimensions
|
||||
}
|
||||
|
||||
mode: int = 0;
|
||||
mode: int = 0
|
||||
when ODIN_OS == "linux" || ODIN_OS == "darwin" {
|
||||
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||
}
|
||||
|
||||
fd, fderr := open(filename, flags, mode);
|
||||
fd, fderr := open(filename, flags, mode)
|
||||
if fderr != 0 {
|
||||
return E_General.Cannot_Open_File;
|
||||
return E_General.Cannot_Open_File
|
||||
}
|
||||
defer close(fd);
|
||||
defer close(fd)
|
||||
|
||||
magic := Signature;
|
||||
magic := Signature
|
||||
|
||||
write_ptr(fd, &magic, 8);
|
||||
write_ptr(fd, &magic, 8)
|
||||
|
||||
ihdr := IHDR{
|
||||
width = u32be(width),
|
||||
@@ -465,61 +465,61 @@ when false {
|
||||
compression_method = 0,
|
||||
filter_method = 0,
|
||||
interlace_method = .None,
|
||||
};
|
||||
}
|
||||
|
||||
switch channels {
|
||||
case 1: ihdr.color_type = Color_Type{};
|
||||
case 2: ihdr.color_type = Color_Type{.Alpha};
|
||||
case 3: ihdr.color_type = Color_Type{.Color};
|
||||
case 4: ihdr.color_type = Color_Type{.Color, .Alpha};
|
||||
case 1: ihdr.color_type = Color_Type{}
|
||||
case 2: ihdr.color_type = Color_Type{.Alpha}
|
||||
case 3: ihdr.color_type = Color_Type{.Color}
|
||||
case 4: ihdr.color_type = Color_Type{.Color, .Alpha}
|
||||
case:// Unhandled
|
||||
return E_PNG.Unknown_Color_Type;
|
||||
return E_PNG.Unknown_Color_Type
|
||||
}
|
||||
h := make_chunk(ihdr, .IHDR);
|
||||
write_chunk(fd, h);
|
||||
h := make_chunk(ihdr, .IHDR)
|
||||
write_chunk(fd, h)
|
||||
|
||||
bytes_needed := width * height * int(channels) + height;
|
||||
filter_bytes := mem.make_dynamic_array_len_cap([dynamic]u8, bytes_needed, bytes_needed, context.allocator);
|
||||
defer delete(filter_bytes);
|
||||
bytes_needed := width * height * int(channels) + height
|
||||
filter_bytes := mem.make_dynamic_array_len_cap([dynamic]u8, bytes_needed, bytes_needed, context.allocator)
|
||||
defer delete(filter_bytes)
|
||||
|
||||
i := 0; j := 0;
|
||||
i := 0; j := 0
|
||||
// Add a filter byte 0 per pixel row
|
||||
for y := 0; y < height; y += 1 {
|
||||
filter_bytes[j] = 0; j += 1;
|
||||
filter_bytes[j] = 0; j += 1
|
||||
for x := 0; x < width; x += 1 {
|
||||
for z := 0; z < channels; z += 1 {
|
||||
filter_bytes[j+z] = image.pixels[i+z];
|
||||
filter_bytes[j+z] = image.pixels[i+z]
|
||||
}
|
||||
i += channels; j += channels;
|
||||
i += channels; j += channels
|
||||
}
|
||||
}
|
||||
assert(j == bytes_needed);
|
||||
assert(j == bytes_needed)
|
||||
|
||||
a: []u8 = filter_bytes[:];
|
||||
a: []u8 = filter_bytes[:]
|
||||
|
||||
out_buf: ^[dynamic]u8;
|
||||
defer free(out_buf);
|
||||
out_buf: ^[dynamic]u8
|
||||
defer free(out_buf)
|
||||
|
||||
ctx := zlib.ZLIB_Context{
|
||||
in_buf = &a,
|
||||
out_buf = out_buf,
|
||||
};
|
||||
err = zlib.write_zlib_stream_from_memory(&ctx);
|
||||
}
|
||||
err = zlib.write_zlib_stream_from_memory(&ctx)
|
||||
|
||||
b: []u8;
|
||||
b: []u8
|
||||
if err == nil {
|
||||
b = ctx.out_buf[:];
|
||||
b = ctx.out_buf[:]
|
||||
} else {
|
||||
return err;
|
||||
return err
|
||||
}
|
||||
|
||||
idat := make_chunk(b, .IDAT);
|
||||
idat := make_chunk(b, .IDAT)
|
||||
|
||||
write_chunk(fd, idat);
|
||||
write_chunk(fd, idat)
|
||||
|
||||
iend := make_chunk([]u8{}, .IEND);
|
||||
write_chunk(fd, iend);
|
||||
iend := make_chunk([]u8{}, .IEND)
|
||||
write_chunk(fd, iend)
|
||||
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
+580
-580
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user