diff --git a/core/image/qoi/qoi.odin b/core/image/qoi/qoi.odin index c157e8099..fdbaab686 100644 --- a/core/image/qoi/qoi.odin +++ b/core/image/qoi/qoi.odin @@ -210,11 +210,6 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a context.allocator = allocator options := options - if .alpha_drop_if_present in options || .alpha_premultiply in options { - // TODO: Implement. - // As stated in image/common, unimplemented options are ignored. - } - if .info in options { options |= {.return_metadata, .do_not_decompress_image} options -= {.info} @@ -258,19 +253,19 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a img.width = int(header.width) img.height = int(header.height) - img.channels = 4 + img.channels = 4 if .alpha_add_if_missing in options else int(header.channels) img.depth = 8 if .do_not_decompress_image in options { + img.channels = int(header.channels) return } - bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), 4, 8) + bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8) if !resize(&img.pixels.buf, bytes_needed) { return img, mem.Allocator_Error.Out_Of_Memory } - pixels := mem.slice_data_cast([]RGBA_Pixel, img.pixels.buf[:]) /* Decode loop starts here. @@ -278,6 +273,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a seen: [64]RGBA_Pixel pix := RGBA_Pixel{0, 0, 0, 255} seen[qoi_hash(pix)] = pix + pixels := img.pixels.buf[:] decode: for len(pixels) > 0 { data := image.read_u8(ctx) or_return @@ -330,13 +326,13 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a } case .RUN: - if length := int(data & 63) + 1; length > len(pixels) { + if length := int(data & 63) + 1; (length * img.channels) > len(pixels) { return img, .Corrupt } else { - #no_bounds_check for i in 0.. (subtotal: int) { passed &= dims_pass - hash := hash.crc32(pixels) - error = fmt.tprintf("%v test %v hash is %08x, expected %08x with %v.", file.file, count, hash, test.hash, test.options) - expect(t, test.hash == hash, error) + png_hash := hash.crc32(pixels) + error = fmt.tprintf("%v test %v hash is %08x, expected %08x with %v.", file.file, count, png_hash, test.hash, test.options) + expect(t, test.hash == png_hash, error) + + passed &= test.hash == png_hash + + // Roundtrip through QOI to test the QOI encoder and decoder. + if passed && img.depth == 8 && (img.channels == 3 || img.channels == 4) { + qoi_buffer: bytes.Buffer + defer bytes.buffer_destroy(&qoi_buffer) + qoi_save_err := qoi.save(&qoi_buffer, img) + + error = fmt.tprintf("%v test %v QOI save failed with %v.", file.file, count, qoi_save_err) + expect(t, qoi_save_err == nil, error) + + if qoi_save_err == nil { + qoi_img, qoi_load_err := qoi.load(qoi_buffer.buf[:]) + defer qoi.destroy(qoi_img) + + error = fmt.tprintf("%v test %v QOI load failed with %v.", file.file, count, qoi_load_err) + expect(t, qoi_load_err == nil, error) + + qoi_hash := hash.crc32(qoi_img.pixels.buf[:]) + error = fmt.tprintf("%v test %v QOI load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, qoi_hash, png_hash, test.options) + expect(t, qoi_hash == png_hash, error) + } + } - passed &= test.hash == hash if .return_metadata in test.options { if v, ok := img.metadata.(^image.PNG_Info); ok {