Remove unneeded semicolons from the core library

This commit is contained in:
gingerBill
2021-08-31 22:21:13 +01:00
parent b176af2742
commit 251da264ed
187 changed files with 27227 additions and 27227 deletions
+35 -35
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff