aboutsummaryrefslogtreecommitdiff
path: root/core/image
diff options
context:
space:
mode:
authorLaytan Laats <laytanlaats@hotmail.com>2024-09-03 19:59:04 +0200
committerLaytan Laats <laytanlaats@hotmail.com>2024-09-03 19:59:04 +0200
commit288312a8126d71fae26c9d62a8cd342d830e1c5f (patch)
treeaa56a083e0222975888a24cf8d755b7d0a4f1bc0 /core/image
parent0e6109e171d24b3bb17289219ae3b482c24f2460 (diff)
core: improve package doc comments for the documentation generator
Diffstat (limited to 'core/image')
-rw-r--r--core/image/png/doc.odin348
-rw-r--r--core/image/png/example.odin351
-rw-r--r--core/image/png/helpers.odin1
-rw-r--r--core/image/png/png.odin5
-rw-r--r--core/image/qoi/qoi.odin2
5 files changed, 351 insertions, 356 deletions
diff --git a/core/image/png/doc.odin b/core/image/png/doc.odin
new file mode 100644
index 000000000..623c13077
--- /dev/null
+++ b/core/image/png/doc.odin
@@ -0,0 +1,348 @@
+/*
+package png implements a PNG image reader
+
+The PNG specification is at [[ https://www.w3.org/TR/PNG/ ]].
+
+Example:
+ package main
+
+ import "core:image"
+ // import "core:image/png"
+ import "core:bytes"
+ import "core:fmt"
+
+ // For PPM writer
+ import "core:mem"
+ import "core:os"
+
+ main :: proc() {
+ track := mem.Tracking_Allocator{}
+ mem.tracking_allocator_init(&track, context.allocator)
+
+ context.allocator = mem.tracking_allocator(&track)
+
+ demo()
+
+ if len(track.allocation_map) > 0 {
+ fmt.println("Leaks:")
+ for _, v in track.allocation_map {
+ fmt.printf("\t%v\n\n", v)
+ }
+ }
+ }
+
+ demo :: proc() {
+ file: string
+
+ options := image.Options{.return_metadata}
+ err: image.Error
+ img: ^image.Image
+
+ file = "../../../misc/logo-slim.png"
+
+ 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 {
+ fmt.printf("Image: %vx%vx%v, %v-bit.\n", img.width, img.height, img.channels, img.depth)
+
+ if v, ok := img.metadata.(^image.PNG_Info); ok {
+ // 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:
+ if t, t_ok := core_time(c); t_ok {
+ fmt.printf("[tIME]: %v\n", t)
+ }
+ case .gAMA:
+ if gama, gama_ok := gamma(c); gama_ok {
+ fmt.printf("[gAMA]: %v\n", gama)
+ }
+ case .pHYs:
+ if phys, phys_ok := phys(c); phys_ok {
+ 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)
+ } else {
+ 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)
+ 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)
+ } else {
+ fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text)
+ }
+ }
+ defer text_destroy(res)
+ case .bKGD:
+ fmt.printf("[bKGD] %v\n", img.background)
+ case .eXIf:
+ if res, ok_exif := exif(c); 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)
+ }
+ case .PLTE:
+ if plte, plte_ok := plte(c); plte_ok {
+ fmt.printf("[PLTE] %v\n", plte)
+ } else {
+ fmt.printf("[PLTE] Error\n")
+ }
+ case .hIST:
+ if res, ok_hist := hist(c); ok_hist {
+ fmt.printf("[hIST] %v\n", res)
+ }
+ case .cHRM:
+ if res, ok_chrm := chrm(c); ok_chrm {
+ fmt.printf("[cHRM] %v\n", res)
+ }
+ case .sPLT:
+ res, ok_splt := splt(c)
+ if ok_splt {
+ fmt.printf("[sPLT] %v\n", res)
+ }
+ splt_destroy(res)
+ case .sBIT:
+ if res, ok_sbit := sbit(c); ok_sbit {
+ fmt.printf("[sBIT] %v\n", res)
+ }
+ case .iCCP:
+ res, ok_iccp := iccp(c)
+ if ok_iccp {
+ fmt.printf("[iCCP] %v\n", res)
+ }
+ iccp_destroy(res)
+ case .sRGB:
+ if res, ok_srgb := srgb(c); ok_srgb {
+ 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)
+ }
+ }
+ }
+ }
+
+ fmt.printf("Done parsing metadata.\n")
+
+ 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.")
+ } else {
+ fmt.println("Error saving out.ppm.")
+ fmt.println(img)
+ }
+ }
+ }
+
+ // Crappy PPM writer used during testing. Don't use in production.
+ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: bool) {
+
+ _bg :: proc(bg: Maybe([3]u16), x, y: int, high := true) -> (res: [3]u16) {
+ if v, ok := bg.?; ok {
+ res = v
+ } else {
+ if high {
+ l := u16(30 * 256 + 30)
+
+ if (x & 4 == 0) ~ (y & 4 == 0) {
+ res = [3]u16{l, 0, l}
+ } else {
+ res = [3]u16{l >> 1, 0, l >> 1}
+ }
+ } else {
+ if (x & 4 == 0) ~ (y & 4 == 0) {
+ res = [3]u16{30, 30, 30}
+ } else {
+ res = [3]u16{15, 15, 15}
+ }
+ }
+ }
+ return
+ }
+
+ // profiler.timed_proc();
+ using image
+ using os
+
+ flags: int = O_WRONLY|O_CREATE|O_TRUNC
+
+ 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[:])
+ #no_bounds_check for v, i in input {
+ output[i] = u16be(v)
+ }
+ }
+ }
+
+ pix := bytes.buffer_to_bytes(&img.pixels)
+
+ if len(pix) == 0 || len(pix) < image.width * image.height * int(image.channels) {
+ return false
+ }
+
+ 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, err := open(filename, flags, mode)
+ if err != nil {
+ return false
+ }
+ defer close(fd)
+
+ write_string(fd,
+ fmt.tprintf("P6\n%v %v\n%v\n", width, height, uint(1 << uint(depth) - 1)),
+ )
+
+ if channels == 3 {
+ // We don't handle transparency here...
+ write_ptr(fd, raw_data(pix), len(pix))
+ } else {
+ 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)
+
+ 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[:])
+ #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:]
+ }
+ } else {
+ 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
+ }
+ }
+ 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[:])
+
+ bgcol := img.background
+
+ #no_bounds_check for len(p16) != 0 {
+ r := f64(u16(p16[0]))
+ bg: f64
+ if bgcol != nil {
+ v := bgcol.([3]u16)[0]
+ bg = f64(v)
+ }
+ 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)
+
+ p16 = p16[2:]
+ o16 = o16[3:]
+ }
+ } else {
+ 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
+ }
+ }
+ 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[:])
+
+ #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
+
+ 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)
+
+ p16 = p16[4:]
+ o16 = o16[3:]
+ }
+ } else {
+ o := 0
+
+ for i := 0; i < len(pix); i += 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])}
+
+ 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
+ }
+ }
+ write_ptr(fd, raw_data(op.buf), len(op.buf))
+ } else {
+ return false
+ }
+ }
+ return true
+ }
+*/
+package png
diff --git a/core/image/png/example.odin b/core/image/png/example.odin
deleted file mode 100644
index ce491978b..000000000
--- a/core/image/png/example.odin
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
- Made available under Odin's BSD-3 license.
-
- List of contributors:
- Jeroen van Rijn: Initial implementation.
- Ginger Bill: Cosmetic changes.
-
- An example of how to use `load`.
-*/
-//+build ignore
-package png
-
-import "core:image"
-// import "core:image/png"
-import "core:bytes"
-import "core:fmt"
-
-// For PPM writer
-import "core:mem"
-import "core:os"
-
-main :: proc() {
- track := mem.Tracking_Allocator{}
- mem.tracking_allocator_init(&track, context.allocator)
-
- context.allocator = mem.tracking_allocator(&track)
-
- demo()
-
- if len(track.allocation_map) > 0 {
- fmt.println("Leaks:")
- for _, v in track.allocation_map {
- fmt.printf("\t%v\n\n", v)
- }
- }
-}
-
-demo :: proc() {
- file: string
-
- options := image.Options{.return_metadata}
- err: image.Error
- img: ^image.Image
-
- file = "../../../misc/logo-slim.png"
-
- 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 {
- fmt.printf("Image: %vx%vx%v, %v-bit.\n", img.width, img.height, img.channels, img.depth)
-
- if v, ok := img.metadata.(^image.PNG_Info); ok {
- // 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:
- if t, t_ok := core_time(c); t_ok {
- fmt.printf("[tIME]: %v\n", t)
- }
- case .gAMA:
- if gama, gama_ok := gamma(c); gama_ok {
- fmt.printf("[gAMA]: %v\n", gama)
- }
- case .pHYs:
- if phys, phys_ok := phys(c); phys_ok {
- 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)
- } else {
- 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)
- 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)
- } else {
- fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text)
- }
- }
- defer text_destroy(res)
- case .bKGD:
- fmt.printf("[bKGD] %v\n", img.background)
- case .eXIf:
- if res, ok_exif := exif(c); 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)
- }
- case .PLTE:
- if plte, plte_ok := plte(c); plte_ok {
- fmt.printf("[PLTE] %v\n", plte)
- } else {
- fmt.printf("[PLTE] Error\n")
- }
- case .hIST:
- if res, ok_hist := hist(c); ok_hist {
- fmt.printf("[hIST] %v\n", res)
- }
- case .cHRM:
- if res, ok_chrm := chrm(c); ok_chrm {
- fmt.printf("[cHRM] %v\n", res)
- }
- case .sPLT:
- res, ok_splt := splt(c)
- if ok_splt {
- fmt.printf("[sPLT] %v\n", res)
- }
- splt_destroy(res)
- case .sBIT:
- if res, ok_sbit := sbit(c); ok_sbit {
- fmt.printf("[sBIT] %v\n", res)
- }
- case .iCCP:
- res, ok_iccp := iccp(c)
- if ok_iccp {
- fmt.printf("[iCCP] %v\n", res)
- }
- iccp_destroy(res)
- case .sRGB:
- if res, ok_srgb := srgb(c); ok_srgb {
- 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)
- }
- }
- }
- }
-
- fmt.printf("Done parsing metadata.\n")
-
- 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.")
- } else {
- fmt.println("Error saving out.ppm.")
- fmt.println(img)
- }
- }
-}
-
-// Crappy PPM writer used during testing. Don't use in production.
-write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: bool) {
-
- _bg :: proc(bg: Maybe([3]u16), x, y: int, high := true) -> (res: [3]u16) {
- if v, ok := bg.?; ok {
- res = v
- } else {
- if high {
- l := u16(30 * 256 + 30)
-
- if (x & 4 == 0) ~ (y & 4 == 0) {
- res = [3]u16{l, 0, l}
- } else {
- res = [3]u16{l >> 1, 0, l >> 1}
- }
- } else {
- if (x & 4 == 0) ~ (y & 4 == 0) {
- res = [3]u16{30, 30, 30}
- } else {
- res = [3]u16{15, 15, 15}
- }
- }
- }
- return
- }
-
- // profiler.timed_proc();
- using image
- using os
-
- flags: int = O_WRONLY|O_CREATE|O_TRUNC
-
- 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[:])
- #no_bounds_check for v, i in input {
- output[i] = u16be(v)
- }
- }
- }
-
- pix := bytes.buffer_to_bytes(&img.pixels)
-
- if len(pix) == 0 || len(pix) < image.width * image.height * int(image.channels) {
- return false
- }
-
- 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, err := open(filename, flags, mode)
- if err != nil {
- return false
- }
- defer close(fd)
-
- write_string(fd,
- fmt.tprintf("P6\n%v %v\n%v\n", width, height, uint(1 << uint(depth) - 1)),
- )
-
- if channels == 3 {
- // We don't handle transparency here...
- write_ptr(fd, raw_data(pix), len(pix))
- } else {
- 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)
-
- 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[:])
- #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:]
- }
- } else {
- 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
- }
- }
- 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[:])
-
- bgcol := img.background
-
- #no_bounds_check for len(p16) != 0 {
- r := f64(u16(p16[0]))
- bg: f64
- if bgcol != nil {
- v := bgcol.([3]u16)[0]
- bg = f64(v)
- }
- 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)
-
- p16 = p16[2:]
- o16 = o16[3:]
- }
- } else {
- 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
- }
- }
- 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[:])
-
- #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
-
- 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)
-
- p16 = p16[4:]
- o16 = o16[3:]
- }
- } else {
- o := 0
-
- for i := 0; i < len(pix); i += 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])}
-
- 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
- }
- }
- write_ptr(fd, raw_data(op.buf), len(op.buf))
- } else {
- return false
- }
- }
- return true
-}
diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin
index 7b6367694..f094b54a9 100644
--- a/core/image/png/helpers.odin
+++ b/core/image/png/helpers.odin
@@ -8,6 +8,7 @@
These are a few useful utility functions to work with PNG images.
*/
+
package png
import "core:image"
diff --git a/core/image/png/png.odin b/core/image/png/png.odin
index 177269722..02aef1087 100644
--- a/core/image/png/png.odin
+++ b/core/image/png/png.odin
@@ -8,9 +8,6 @@
*/
-// package png implements a PNG image reader
-//
-// The PNG specification is at https://www.w3.org/TR/PNG/.
//+vet !using-stmt
package png
@@ -1619,4 +1616,4 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
@(init, private)
_register :: proc() {
image.register(.PNG, load_from_bytes, destroy)
-} \ No newline at end of file
+}
diff --git a/core/image/qoi/qoi.odin b/core/image/qoi/qoi.odin
index 5cf252fcc..6b6149e60 100644
--- a/core/image/qoi/qoi.odin
+++ b/core/image/qoi/qoi.odin
@@ -9,7 +9,7 @@
// package qoi implements a QOI image reader
//
-// The QOI specification is at https://qoiformat.org.
+// The QOI specification is at [[ https://qoiformat.org ]].
package qoi
import "core:image"