|
@@ -396,132 +396,4 @@ exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) {
|
|
|
General helper functions
|
|
|
*/
|
|
|
|
|
|
-compute_buffer_size :: image.compute_buffer_size
|
|
|
-
|
|
|
-/*
|
|
|
- PNG save helpers
|
|
|
-*/
|
|
|
-
|
|
|
-when false {
|
|
|
-
|
|
|
- make_chunk :: proc(c: any, t: Chunk_Type) -> (res: Chunk) {
|
|
|
-
|
|
|
- data: []u8
|
|
|
- if v, ok := c.([]u8); ok {
|
|
|
- data = v
|
|
|
- } else {
|
|
|
- data = mem.any_to_bytes(c)
|
|
|
- }
|
|
|
-
|
|
|
- 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))
|
|
|
- // Extend the CRC with the data
|
|
|
- res.crc = u32be(hash.crc32(data, crc))
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- write_chunk :: proc(fd: os.Handle, chunk: Chunk) {
|
|
|
- c := chunk
|
|
|
- // Write length + type
|
|
|
- os.write_ptr(fd, &c.header, 8)
|
|
|
- // Write data
|
|
|
- os.write_ptr(fd, mem.raw_data(c.data), int(c.header.length))
|
|
|
- // Write CRC32
|
|
|
- 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
|
|
|
-
|
|
|
- if len(image.pixels) == 0 || len(image.pixels) < image.width * image.height * int(image.channels) {
|
|
|
- return .Invalid_Image_Dimensions
|
|
|
- }
|
|
|
-
|
|
|
- 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
|
|
|
- }
|
|
|
-
|
|
|
- fd, fderr := open(filename, flags, mode)
|
|
|
- if fderr != nil {
|
|
|
- return .Cannot_Open_File
|
|
|
- }
|
|
|
- defer close(fd)
|
|
|
-
|
|
|
- magic := Signature
|
|
|
-
|
|
|
- write_ptr(fd, &magic, 8)
|
|
|
-
|
|
|
- ihdr := IHDR{
|
|
|
- width = u32be(width),
|
|
|
- height = u32be(height),
|
|
|
- bit_depth = depth,
|
|
|
- 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:// Unhandled
|
|
|
- return .Unknown_Color_Type
|
|
|
- }
|
|
|
- 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)
|
|
|
-
|
|
|
- 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
|
|
|
- for x := 0; x < width; x += 1 {
|
|
|
- for z := 0; z < channels; z += 1 {
|
|
|
- filter_bytes[j+z] = image.pixels[i+z]
|
|
|
- }
|
|
|
- i += channels; j += channels
|
|
|
- }
|
|
|
- }
|
|
|
- assert(j == bytes_needed)
|
|
|
-
|
|
|
- a: []u8 = filter_bytes[:]
|
|
|
-
|
|
|
- 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)
|
|
|
-
|
|
|
- b: []u8
|
|
|
- if err == nil {
|
|
|
- b = ctx.out_buf[:]
|
|
|
- } else {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- idat := make_chunk(b, .IDAT)
|
|
|
-
|
|
|
- write_chunk(fd, idat)
|
|
|
-
|
|
|
- iend := make_chunk([]u8{}, .IEND)
|
|
|
- write_chunk(fd, iend)
|
|
|
-
|
|
|
- return nil
|
|
|
- }
|
|
|
-}
|
|
|
+compute_buffer_size :: image.compute_buffer_size
|