Skip to content
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

Cannot change jpeg_width and jpeg_height without reflection #9

Open
Dwedit opened this issue Jun 12, 2022 · 3 comments
Open

Cannot change jpeg_width and jpeg_height without reflection #9

Dwedit opened this issue Jun 12, 2022 · 3 comments

Comments

@Dwedit
Copy link

Dwedit commented Jun 12, 2022

I was working on a tool that let you losslessly merge two JPEGs together by putting one on top of the other. This can be done if they were saved with the same compression settings.

I did manage to get it working correctly, but I encountered one problem with the library when I had to save the JPEG file.

var decompress1 = new jpeg_decompress_struct();  //Create 'decompress' object
decompress1.jpeg_stdio_src(inputFileStream1);  //Load a JPEG file
decompress1.jpeg_read_header(true);  //Load the header
var compress = new jpeg_compress_struct();  //Create 'compress' object
compress.jpeg_stdio_dest(outputStream);  //Assign the output stream
decompress1.jpeg_copy_critical_parameters(compress);  //Copy the critical parameters
compress.Image_width = outputWidth;  //Set output width
compress.Image_height = outputHeight;  //Set output height
compress.jpeg_write_coefficients(outputBlocks);  //Set Output DCT blocks
compress.jpeg_finish_compress();  //Output the JPEG file

The problem happens when you call jpeg_finish_compress, it ignores the public Image_width and Image_height fields. Instead, it uses the private fields jpeg_width and jpeg_height to determine what dimensions to use for the output file.

In order to get the program to work, I needed to use reflection to write to those private members.

@Bobrovsky
Copy link
Member

Please take a look at source code of jpeg_copy_critical_parameters . This should give you an idea how to work around the issue.

The jpeg_width and jpeg_height fields are internal because the plan is to calculate them in jpeg_calc_jpeg_dimensions or copy in jpeg_copy_critical_parameters. Other use cases are not supported at the moment.

@Dwedit
Copy link
Author

Dwedit commented Jun 14, 2022

Just peeked at the code for jpeg_write_coefficients.

The code path that could possibly reach jpeg_calc_jpeg_dimensions is disabled.
jpeg_write_coefficients -> transencode_master_selection -> jinit_c_master_control(transcode_only: true) -> initial_setup(transcode_only: true)

initial_setup is the function that could call jpeg_calc_jpeg_dimensions, but because transcode_only = true, it does not call it. So Image_width and Image_height never get re-read, and the private members jpeg_width and jpeg_height remain at their previous values.

It just so happens that poking the private jpeg_width and jpeg_height values before calling jpeg_write_coefficients will make everything work correctly, but it only works because jpeg_write_coefficients is calling initial_setup.


Another point of consideration is that for jpeg_write_coefficients, the dimensions of the blocks is provided in the array itself. Luma plane is always in 8x8 blocks and is never subsampled. So the padded image dimensions could be determined by the luma plane, and the non-padded image dimensions can only be be up to 7 pixels smaller.

Image_width and Image_height could be checked at this time, and if they are not valid, could be reset to the block dimensions.

Then transcode_only = true could be removed as well, then jpeg_write_coefficients would have all the information it needs to set the Image_width, Image_height, jpeg_width, and jpeg_height variables.

@Bobrovsky
Copy link
Member

Bobrovsky commented Jun 14, 2022

I am not sure I follow. Could you please clarify what you suggest to do?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants