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

Support for chroma subsampling other than 4:2:0 #6

Open
FelixKras opened this issue Jul 29, 2020 · 6 comments
Open

Support for chroma subsampling other than 4:2:0 #6

FelixKras opened this issue Jul 29, 2020 · 6 comments

Comments

@FelixKras
Copy link

I have tried compressing a raw 24 bpp image represented by an byte array,
I have tried both the JpegImage API and the low level jpeg_compress_struct structure,
I even tried changing the internal jpeg_set_colorspace_SET_COMP() values
i either get 4:2:0 chroma image or "Not implemented exception"
my input colorspace is RGB
my output colorspace is YcBcR

@shibaev
Copy link
Member

shibaev commented Jul 30, 2020

Could you please provide a sample code and image to reproduce the issue?

@FelixKras
Copy link
Author

Here's the code:

int[] LumTable = new int[]
            {
                16, 11, 10, 16, 24, 40, 51, 61,
                12, 12, 14, 19, 26, 58, 60, 55,
                14, 13, 16, 24, 40, 57, 69, 56,
                14, 17, 22, 29, 51, 87, 80, 62,
                18, 22, 37, 56, 68, 109, 103, 77,
                24, 35, 55, 64, 81, 104, 113, 92,
                49, 64, 78, 87, 103, 121, 120, 101,
                72, 92, 95, 98, 112, 100, 103, 99
            };
            int[] ChromaTable = new int[]
            {
                255, 255, 255, 255, 255, 255, 255, 255,
                255, 255, 255, 255, 255, 255, 255, 255,
                255, 255, 255, 255, 255, 255, 255, 255,
                255, 255, 255, 255, 255, 255, 255, 255,
                255, 255, 255, 255, 255, 255, 255, 255,
                255, 255, 255, 255, 255, 255, 255, 255,
                255, 255, 255, 255, 255, 255, 255, 255,
                255, 255, 255, 255, 255, 255, 255, 255
            };


            try
            {
                Bitmap bmp = new Bitmap(@"c:\temp\chromatestInput.jpg");
                int width = bmp.Width;
                int height = bmp.Height;
                int bpp = 3; //bytes per pixel
                byte[] testImage = new byte[height * width * bpp];
                BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite,
                    bmp.PixelFormat);
                Marshal.Copy(bmData.Scan0, testImage, 0, testImage.Length);
                bmp.UnlockBits(bmData);

                int quality = 100;

                using (var fs = new FileStream(@"c:\temp\chromatestOutput.jpg", FileMode.Create))
                {
                    BitMiracle.LibJpeg.Classic.jpeg_error_mgr err = new jpeg_error_mgr();
                    BitMiracle.LibJpeg.Classic.jpeg_compress_struct cmpStr = new jpeg_compress_struct(err);
                    cmpStr.jpeg_stdio_dest(fs);
                    cmpStr.Image_width = width;
                    cmpStr.Image_height = height;
                    cmpStr.Input_components = bpp;

                    cmpStr.jpeg_set_defaults();
                    cmpStr.In_color_space = J_COLOR_SPACE.JCS_RGB;
                    cmpStr.jpeg_set_colorspace(J_COLOR_SPACE.JCS_YCbCr);
                    cmpStr.jpeg_set_quality(quality, false);
                    cmpStr.Optimize_coding = false;
                    cmpStr.jpeg_add_quant_table(0, LumTable, 100, true);
                    cmpStr.jpeg_add_quant_table(1, ChromaTable, 100, true);
                    cmpStr.Dct_method = J_DCT_METHOD.JDCT_IFAST;


                    byte[][] rowlines = new byte[1][];
                    rowlines[0] = new byte[cmpStr.Image_width * bpp];
                    cmpStr.jpeg_start_compress(true);
                    for (int i = 0; i < height && cmpStr.Next_scanline < cmpStr.Image_height; i++)
                    {
                        Buffer.BlockCopy(testImage,i*cmpStr.Image_width*bpp,rowlines[0]
                            ,0,cmpStr.Image_width*bpp);
                        cmpStr.jpeg_write_scanlines(rowlines, 1);
                    }
                    cmpStr.jpeg_finish_compress();
                }
            }
            catch (Exception exception)
            {
                System.Console.WriteLine(exception);
                throw;
            }

and the test file (input)
the code generates an output file
chromaTestInput

@FelixKras
Copy link
Author

@shibaev
Any progress?

@shibaev
Copy link
Member

shibaev commented Aug 25, 2020

Did you attach the chromatestInput.jpg? It looks that the only attachment https://user-images.githubusercontent.com/42567361/88899292-8ba3a700-d256-11ea-9060-0719a61e9ada.jpg corresponds to chromatestOutput.jpg.

Also please clarify what is expected result for you? I.e. what is wrong with the https://user-images.githubusercontent.com/42567361/88899292-8ba3a700-d256-11ea-9060-0719a61e9ada.jpg image.

@FelixKras
Copy link
Author

The attached image is an input image (it was meant to appear a line above)
the code generates an output (not attached, it is generated by the code)
the expected result is a 4:2:2 chroma subsampling (or any other than 4:2:0)

@shibaev
Copy link
Member

shibaev commented Sep 1, 2020

Thank you for your explanation. Currently, LibJpeg.Net only supports 2x2 (4:2:0) and 1x1 (4:4:4) subsampling levels. You can produce 1x1 output using these lines:

var comp0 = cmpStr.Component_info[0];
comp0.V_samp_factor = 1;
comp0.H_samp_factor = 1;

Other variations are currently not implemented. Look at jpeg_fdct_*x* methods in /LibJpeg/Classic/Internal/jpeg_forward_dct.cs

However, the original libjpeg supports other subsampling levels. You can look at the latest version from http://www.ijg.org/.

Unfortunately, this feature has a low priority for us. We would appreciate a pull request that:

  1. Migrates logic for some or all missing jpeg_fdct_*x* methods from the original libjpeg to our managed version. I cannot guarantee that migration of jpeg_fdct_*x* is enough, so be ready to migrate some other related code.
  2. Includes tests covering the migrated code

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