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

Add ICO and CUR file decoder. #2579

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open

Conversation

frg2089
Copy link

@frg2089 frg2089 commented Nov 8, 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

  • Make the Bmp Decoder Core to support ICO's data.
  • 🎉 Add ICO Encoder.
  • Add ICO Decoder.
  • Add ICO Image Format Detector.
  • 🎉 Add CUR Encoder.
  • Add CUR Decoder.
  • Add CUR Image Format Detector.

Some Questions

Warning

We don't support bmp palettes yet.

@CLAassistant
Copy link

CLAassistant commented Nov 8, 2023

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@Poker-sang
Copy link
Contributor

Poker-sang commented Nov 8, 2023

Even though there is no magic head for ICOs, should we still provide IcoImageFormatDetector as well? In order to support Image.Load<TPixel>().

And should we name the classes with Ico instead of Icon?

src/ImageSharp/Image.cs Outdated Show resolved Hide resolved
@JimBobSquarePants
Copy link
Member

Even though there is no magic head for ICOs, should we still provide IcoImageFormatDetector as well? In order to support Image.Load<TPixel>().

And should we name the classes with Ico instead of Icon?

How do you identify without leading bytes?

@Poker-sang
Copy link
Contributor

Poker-sang commented Nov 8, 2023

Maybe we can combine an ICODir and an entry, and think of it as the header of an ICO file.

Or we just provide a decoder, but this decoder will not be used without specification.

@frg2089
Copy link
Author

frg2089 commented Nov 8, 2023

Maybe we can combine an ICODir and an entry, and think of it as the header of an ICO file.

Or we just provide a decoder, but this decoder will not be used without specification.

I think we can do without providing IconImageFormatDetector.
Because nobody cares if unknown streams are ICOs. They are usually not transmitted without filename.
So we should just provide a decoder and use it directly.

like this

using SixLabors.ImageSharp.Formats.Icon;

async using var fs = File.OpenRead(@"xxx.ico");
var ico = IconDecoder.Instance.Decode(new (), fs);

@frg2089 frg2089 marked this pull request as draft November 8, 2023 12:43
@frg2089 frg2089 force-pushed the feat/icon branch 2 times, most recently from 6f211c1 to a70c1ca Compare November 9, 2023 14:47
@frg2089 frg2089 marked this pull request as ready for review November 9, 2023 14:50
@Poker-sang
Copy link
Contributor

Poker-sang commented Nov 9, 2023

We actually have an open discussion supporting tiffs with multisize frames. It would be good to split any changes to the tiff decoder out so we can draw the pixel data on the frame.

@JimBobSquarePants Yes. I have reverted all changes to tiff files.

@frg2089 frg2089 marked this pull request as draft November 10, 2023 13:47
@frg2089 frg2089 marked this pull request as ready for review November 10, 2023 14:30
Copy link
Member

@JimBobSquarePants JimBobSquarePants left a comment

Choose a reason for hiding this comment

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

Thanks for this, your efforts are really appreciated! There's a lot to discuss.

Some notes...

I don't think it's a good idea to merge the two formats. We're creating unnecessary ambiguity. If you look at format metadata, we avoid exposing unconstrained configuration values.

It's imperative that the pixel data is drawn on the frame and not resized. Position 0,0, seems sane as an origin. Any other behavior such as resizing or introducing new image types or editing existing signifies a major breaking change for the library.

We need an encoder. I can't accept code against main without one as we need to ensure that we have covered encoding requirements in the format design.

I'll be honest and say this won't get merged before V4. There's a lot to do to ensure that the decoder is safe (I haven't checked bounds handling and EOF detection) and the design practical.

src/ImageSharp/Formats/Ico/IcoConfigurationModule.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoConstants.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoDecoderCore.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoDecoderCore.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoFrameMetadata.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoFrameMetadata.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoMetadata.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoMetadata.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoMetadata.cs Outdated Show resolved Hide resolved
@frg2089 frg2089 marked this pull request as draft November 11, 2023 06:09
Copy link
Member

@JimBobSquarePants JimBobSquarePants left a comment

Choose a reason for hiding this comment

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

You've gone the opposite direction to how I hoped I'm afraid here. Please let me know if you need further guidance and I'll try my best to explain.

.gitattributes Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Bmp/BmpMetadata.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Cur/CurBmpFrameMetadata.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/Common/IcoLikeDecoderCore.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/Common/IcoLikeFrameMetadata.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoBmpFrameMetadata.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoImageFormatDetector.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Ico/IcoPngFrameMetadata.cs Outdated Show resolved Hide resolved
@frg2089
Copy link
Author

frg2089 commented Nov 13, 2023

You've gone the opposite direction to how I hoped I'm afraid here. Please let me know if you need further guidance and I'll try my best to explain.

I refactored the code.
Now it doesn't have the IcoPngFrameMetadata, IcoBmpFrameMetadata and the corresponding Cur variants.
We can use GetFormatMetadata(XXXFormat.Instance) (which isn't there yet) to get specific metadata.
If I'm not doing this the right way, I'm probably not understanding what you're really thinking.

@JimBobSquarePants
Copy link
Member

JimBobSquarePants commented Nov 13, 2023

I'm going to write some code to your fork....

OK. So, I've refactored the base decoder to be more efficient and allow us to gather the correct metadata from the png/bmp frames.

I've added a bunch of TODOs in the code also. Please let me know if anything is not clear.

Copy link
Author

@frg2089 frg2089 left a comment

Choose a reason for hiding this comment

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

I have some questions about how to store PngMetadata and BmpMetadata.

We should store BitsPerPixel property for encoder.
The ICO file may have more than one PNG data.

src/ImageSharp/Formats/Icon/IconDecoderCore.cs Outdated Show resolved Hide resolved
Comment on lines 106 to 102
if (bmpMetadata != null)
{
result.Metadata.SetFormatMetadata(BmpFormat.Instance, bmpMetadata);
}

if (pngMetadata != null)
{
result.Metadata.SetFormatMetadata(PngFormat.Instance, pngMetadata);
}
Copy link
Author

Choose a reason for hiding this comment

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

I think the PNG data may not be the only one. ICO file may have 2 and more PNG data.
So, we should store the PngMetadata in the FrameMetadata instead of the ImageMetadata.

Copy link
Member

Choose a reason for hiding this comment

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

They’re just for easy conversation really. See below re bits per pixel. You may want to capture palette data also

@JimBobSquarePants
Copy link
Member

I have some questions about how to store PngMetadata and BmpMetadata.

We should store BitsPerPixel property for encoder. The ICO file may have more than one PNG data.

I’d store that in the Ico/Cur frame metadata. I’d make it an enum though (it’s a fixed range based on available bmp/png fixes)

@JimBobSquarePants
Copy link
Member

Apologies for the radio silence over the last few weeks. I've been very busy fixing up the animation behavior for v3.1

@frg2089
Copy link
Author

frg2089 commented Dec 14, 2023

Do we have some new ways to save frames of different sizes yet?

@JimBobSquarePants
Copy link
Member

Do we have some new ways to save frames of different sizes yet?

You encode the size stored in the metadata. Pixel buffers can be constrained to regions


protected IconDir FileHeader { get => this.fileHeader; private set => this.fileHeader = value; }

protected IconDirEntry[] Entries { get; private set; } = [];
Copy link
Author

Choose a reason for hiding this comment

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

SA1010
Should I avoid this syntax?

Copy link
Member

Choose a reason for hiding this comment

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

You should be fine now that I've updated the StyleCop version.

@frg2089 frg2089 marked this pull request as ready for review December 14, 2023 15:02
@JimBobSquarePants
Copy link
Member

@frg2089 Thanks for all your effort so far. It's been tricky for me to review as I've just moved house and have no real internet just now. I'll be able to do a proper review next week though.

@JimBobSquarePants
Copy link
Member

I'm going to have a look at how we manage the sizes in the encoding options. I want to come up with the best possible design so I will look for inspiration in other libraries.

frg2089 and others added 20 commits May 23, 2024 08:53
Make BmpDecoderCore support AlphaMask.
link SixLabors#687

Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
- Ico Decoder
- Ico Detector
- Ico Detector UnitTest
- Cur Decoder
- Cur Detector
- Cur Detector UnitTest

Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
but AlphaMask have some problems
…and the case where the stream start position is not 0.
Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
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

4 participants