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

Adding QOI support #2446

Merged
merged 30 commits into from Jul 6, 2023
Merged

Adding QOI support #2446

merged 30 commits into from Jul 6, 2023

Conversation

LuisAlfredo92
Copy link
Contributor

@LuisAlfredo92 LuisAlfredo92 commented May 4, 2023

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

First of all, I'm sorry for being so late to add this, I've been extremely busy :(
Also I took some time to see the code to understand it and do it with the same structure

Then, I've add some files to work with qoi, at this moment it only identifies qoi images and returns the ImageInfo, but I want to make sure that I'm doing this correctly before doing the rest of functions. I've followed the Stylecop rules with Visual Studio Intellisense.

The test images were taken from the official website in the Test images in QOI and PNG format link.

This is about #2403

Could you review it please?

I'm starting to need help because I don't understand the project structure

Everything I added was taken from the specification and structured similarly to PNG and BMP
 I'm going to do some tests before the pull request and add all the functions
Now it identifies qoi images successfully
@CLAassistant
Copy link

CLAassistant commented May 4, 2023

CLA assistant check
All committers have signed the CLA.

Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you already implemented Identify, your next step is probably to make sure it actually works. Here's an example test, you want an equivalent for Qoi:

[Theory]
[InlineData(TestImages.Png.Bpp1, 1)]
[InlineData(TestImages.Png.Gray4Bpp, 4)]
[InlineData(TestImages.Png.Palette8Bpp, 8)]
[InlineData(TestImages.Png.Pd, 24)]
[InlineData(TestImages.Png.Blur, 32)]
[InlineData(TestImages.Png.Rgb48Bpp, 48)]
[InlineData(TestImages.Png.Rgb48BppInterlaced, 48)]
public void Identify(string imagePath, int expectedPixelSize)
{
TestFile testFile = TestFile.Create(imagePath);
using MemoryStream stream = new(testFile.Bytes, false);
ImageInfo imageInfo = Image.Identify(stream);
Assert.NotNull(imageInfo);
Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel);
}

(I recommend to validate image size and stuff like QoiChannels and QoiColorSpace there.)

To make sure the format is recognized by Image.Identify and Image.Load and triggers your decoder, you also need to implement and register a "configuration module":

internal static Configuration CreateDefaultInstance() => new(
new PngConfigurationModule(),
new JpegConfigurationModule(),
new GifConfigurationModule(),
new BmpConfigurationModule(),
new PbmConfigurationModule(),
new TgaConfigurationModule(),
new TiffConfigurationModule(),
new WebpConfigurationModule());

src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs Outdated Show resolved Hide resolved
tests/ImageSharp.Benchmarks/Codecs/Qoi/IdentifyQoi.cs Outdated Show resolved Hide resolved
@antonfirsov
Copy link
Member

There are some some StyleCop complaints breaking the build since we use TreatWarningsAsErrors:
https://github.com/SixLabors/ImageSharp/actions/runs/4885169437/jobs/8735504561?pr=2446

When you will move on to the actual Decode implementation, you want to base your decoder tests on this:

[Theory]
[WithFile(BlackAndWhitePlain, PixelTypes.L8, "pbm")]
[WithFile(BlackAndWhiteBinary, PixelTypes.L8, "pbm")]
[WithFile(GrayscalePlain, PixelTypes.L8, "pgm")]
[WithFile(GrayscalePlainNormalized, PixelTypes.L8, "pgm")]
[WithFile(GrayscaleBinary, PixelTypes.L8, "pgm")]
[WithFile(GrayscaleBinaryWide, PixelTypes.L16, "pgm")]
[WithFile(RgbPlain, PixelTypes.Rgb24, "ppm")]
[WithFile(RgbPlainNormalized, PixelTypes.Rgb24, "ppm")]
[WithFile(RgbBinary, PixelTypes.Rgb24, "ppm")]
public void DecodeReferenceImage<TPixel>(TestImageProvider<TPixel> provider, string extension)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
image.DebugSave(provider, extension: extension);
bool isGrayscale = extension is "pgm" or "pbm";
image.CompareToReferenceOutput(provider, grayscale: isGrayscale);
}

First just make sure visually that DebugSave is saving the right thing. CompareToReferenceOutput would need your reference png to be in the right directory with the right name, we can explain that later.

@LuisAlfredo92
Copy link
Contributor Author

Thanks for the reviewing, I'll correct everything and tell when I start working on the other functions 👍

src/ImageSharp/Formats/Qoi/QoiConstants.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Qoi/QoiConstants.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Qoi/QoiConstants.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Qoi/QoiHeader.cs Show resolved Hide resolved
-Adding validation for size, channels and colorspace
-Refactoring to throw general exceptions
-Creating tests
-Using other better data types
@LuisAlfredo92
Copy link
Contributor Author

Hello again, I can finally work in this again 🎉

I've made the changes you told me, however, I didn't find how to run the tests, so I only added the configurations but didn't test them

Soon I'll try to add the Decode and Encode options

@antonfirsov
Copy link
Member

I didn't find how to run the tests.

You can use dotnet test from the command line:

 dotnet test -f net6.0 --filter FullyQualifiedName~QoiDecoderTests

Or if you are using Visual Studio, they should appear in the Test Explorer window.

-I had several errors about header size comparison and comparing byte arrays, but I've fixed them and tested the Identify function and it works perfect!
@LuisAlfredo92
Copy link
Contributor Author

LuisAlfredo92 commented Jun 20, 2023

There are some some StyleCop complaints breaking the build since we use TreatWarningsAsErrors: https://github.com/SixLabors/ImageSharp/actions/runs/4885169437/jobs/8735504561?pr=2446

When you will move on to the actual Decode implementation, you want to base your decoder tests on this:

[Theory]
[WithFile(BlackAndWhitePlain, PixelTypes.L8, "pbm")]
[WithFile(BlackAndWhiteBinary, PixelTypes.L8, "pbm")]
[WithFile(GrayscalePlain, PixelTypes.L8, "pgm")]
[WithFile(GrayscalePlainNormalized, PixelTypes.L8, "pgm")]
[WithFile(GrayscaleBinary, PixelTypes.L8, "pgm")]
[WithFile(GrayscaleBinaryWide, PixelTypes.L16, "pgm")]
[WithFile(RgbPlain, PixelTypes.Rgb24, "ppm")]
[WithFile(RgbPlainNormalized, PixelTypes.Rgb24, "ppm")]
[WithFile(RgbBinary, PixelTypes.Rgb24, "ppm")]
public void DecodeReferenceImage<TPixel>(TestImageProvider<TPixel> provider, string extension)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
image.DebugSave(provider, extension: extension);
bool isGrayscale = extension is "pgm" or "pbm";
image.CompareToReferenceOutput(provider, grayscale: isGrayscale);
}

First just make sure visually that DebugSave is saving the right thing. CompareToReferenceOutput would need your reference png to be in the right directory with the right name, we can explain that later.

Hello again, I need some help with the tests

When I try to test the Qoi decoder, when it tries to get the extension, qoi image format never appears:
imagen

However, during debugging, it actually is correctly added:
imagen

So I don't know if I must add something else on the code or tests

Just in case, my qoi configuration module adds only a decoder and format detector
imagen

EDIT
I created the encoder class just to add it to the configuration (although it doesn't do anything yet) but still doesn't work

@LuisAlfredo92
Copy link
Contributor Author

Nevermind, I found where the configuration is done
imagen

@JimBobSquarePants
Copy link
Member

Nevermind, I found where the configuration is done imagen

Sorry, didn't see this. Glad you figured it out. Any other questions please let me know!

I need to check phoboslab/qoi#258 because there's a bug with the decoder
See phoboslab/qoi#258 and previous commit
@LuisAlfredo92
Copy link
Contributor Author

Hello!
I've finished the decoder and it passes all the tests 🎉 I've also taken into consideration the edge case and now it works perfectly, however, I'm not sure if I followed correctly the standards of the project, could you check it please?

I'll be working on the encoder now

-Also adding Decode method without TPixel value
-Adding stream end check to decoder (we must discuss if it's necesarry or not)
-formating general code
@LuisAlfredo92 LuisAlfredo92 marked this pull request as ready for review June 28, 2023 22:34
@LuisAlfredo92
Copy link
Contributor Author

Hello again
I've finished encoder, decoder and extensions, and all of them have passed all the tests, but we should discuss some things about the encoder (if it's correct to allow file to start with a QOI_OP_RUN) and decoder (throw an exception when the end of stream doesn't end with seven zero-bytes and one byte with value 1). I wrote some comments if you want to check

I'd like to ask for a review to see if I'm not doing something wrong

Changing formats from 8 to 9
Also adding Modulo64 and 256 to Numerics and optimizing a little bit Encoder
@LuisAlfredo92
Copy link
Contributor Author

Okay, I've done everything you've asked

Is there anything else I should do?

Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see some optimization opportunities in QoiEncoder too, but focusing on functionality first.

src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Qoi/QoiEncoderCore.cs Outdated Show resolved Hide resolved
tests/ImageSharp.Tests/Formats/Qoi/QoiDecoderTests.cs Outdated Show resolved Hide resolved
tests/ImageSharp.Tests/Formats/Qoi/QoiEncoderTests.cs Outdated Show resolved Hide resolved
Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there! A few more suggestions for perf.

src/ImageSharp/Formats/Qoi/QoiEncoderCore.cs Outdated Show resolved Hide resolved
tests/ImageSharp.Benchmarks/Codecs/Qoi/IdentifyQoi.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Qoi/QoiEncoderCore.cs Outdated Show resolved Hide resolved
Also removing benchmark test and fixing a typo in PngEncoderCore
@LuisAlfredo92
Copy link
Contributor Author

LuisAlfredo92 commented Jul 3, 2023

Changes done
I'm pretty excited to see these changes merged into the main project 😄

@LuisAlfredo92
Copy link
Contributor Author

Everything's done 🎉

@JimBobSquarePants JimBobSquarePants added this to the v3.1.0 milestone Jul 5, 2023
@LuisAlfredo92
Copy link
Contributor Author

Is there anything else I could do?

Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to merge now. Thanks a lot for the nice work, and really appreciate the patience for the long review!

@LuisAlfredo92
Copy link
Contributor Author

LuisAlfredo92 commented Jul 6, 2023

Thanks to you all for reviewing the changes so constantly and I'm sorry it took so long, I posted the idea when I was about to get back to school and I was able to do it until the semester finished xD

@JimBobSquarePants
Copy link
Member

Adding an entirely new image format is no small task! Really well done and thanks so much for your efforts!

@JimBobSquarePants JimBobSquarePants merged commit 900e9d0 into SixLabors:main Jul 6, 2023
8 checks passed
@LuisAlfredo92
Copy link
Contributor Author

When you publish the 3.1.0 version, could I add ImageSharp it to the phoboslab/qoi repository README? Maybe on tools or implementations

@antonfirsov
Copy link
Member

Yeah I also wanted to call out that we need to get into that hall of fame after the release.

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

Successfully merging this pull request may close these issues.

None yet

6 participants