-
Notifications
You must be signed in to change notification settings - Fork 119
JPEG Writer #297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JPEG Writer #297
Conversation
mlarouche
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow! A big chunk that will help this project a lot, thanks a ton!
I did make requests for changes, the 2 big ones being pixel format conversion requiring explicit demand from the user and not using Image directly in JPEGWriter, the rest is mostly debug prints that needs to be removed and naming conventions violations.
tests/formats/jpeg_test.zig
Outdated
|
|
||
| // Calculate average delta | ||
| const avg_delta = averageDelta(original, decoded) catch continue; | ||
| std.debug.print("JPEG writer {s} q={d} avg_delta={d:.2} (<= {d:.2})\n", .{ tc.filename, tc.quality, avg_delta, tc.tolerance }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove all debug print in the tests
tests/formats/jpeg_test.zig
Outdated
| const helpers = @import("../helpers.zig"); | ||
| const jpeg = zigimg.formats.jpeg; | ||
| const std = @import("std"); | ||
| const testing = std.testing; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you look at the recent changes I did while migrating to 0.15, you'll see that I replaced almost all aliasing of namespaces. My personal rule is aliasing the module/struct you are testing is okay but the rest should be fully qualified
tests/formats/jpeg_test.zig
Outdated
| const zigimg = @import("zigimg"); | ||
| const Image = zigimg.Image; | ||
| const color = zigimg.color; | ||
| const utils = @import("../../src/formats/jpeg/utils.zig"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't import files from the implementation in the tests. You can migrate the zig zag test into utils.zig directly.
tests/formats/jpeg_test.zig
Outdated
| try testing.expectEqual(img0.width, img1.width); | ||
| try testing.expectEqual(img0.height, img1.height); | ||
|
|
||
| const w = img0.width; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try avoid using single letter variables, it hurts readability.
tests/formats/jpeg_test.zig
Outdated
| const alloc = arena.allocator(); | ||
|
|
||
| // Generous buffer for small test images | ||
| const buf = try alloc.alloc(u8, 1 << 20); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
buf -> buffer
src/formats/jpeg/writer.zig
Outdated
| }; | ||
|
|
||
| // Huffman table specifications | ||
| const theHuffmanSpec = [nHuffIndex]HuffmanSpec{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constant does not respect the naming convention
src/formats/jpeg/writer.zig
Outdated
| }; | ||
|
|
||
| // div returns a/b rounded to the nearest integer, instead of rounded to zero | ||
| fn div(a: i32, b: i32) i32 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you try if @divFloor would work here?
src/formats/jpeg.zig
Outdated
| var jpeg_writer = JPEGWriter.init(writer); | ||
|
|
||
| // Encode the converted image | ||
| try jpeg_writer.encode(converted_image, jpeg_options.quality); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass the PixelStorage, width and height to encode(). You should be able to write JPEG files without using Image. The interface implemented for Image in each format is just a convenience wrapper for the lower levels read() and write() of each format that works with PixelStorage.
src/formats/jpeg/writer.zig
Outdated
| // the tables according to its quality parameter. | ||
| // The values are derived from section K.1 of the spec, after converting from | ||
| // natural to zig-zag order. | ||
| const unscaledQuant = [quant_index][block_size]u8{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a constant, not a function
src/formats/jpeg/writer.zig
Outdated
| /// JPEGWriter handles encoding images to JPEG format | ||
| pub const JPEGWriter = struct { | ||
| writer: *std.Io.Writer, | ||
| err: ?Image.WriteError = null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fail to see why you need to store an error and do early exits when the try keyword already does this for you.
|
Thanks for the detailed review! I believe I got it all. I prefer most of the style changes you recommended and will likely bring them back to my other projects. |
Hi! This PR adds a JPEG encoder. I tried to add the right tests. I ran the encoder over a bunch of random files from the test suite, things seem to convert just fine. The implementation is loosely based on the one in the Go standard library.
Note that many formats are converted to
rgb24orgrayscale8internally before encoding.If it helps, this test program will write a JPEG then use the existing reader to check that it's valid.