SixLabors / ImageSharp

:camera: A modern, cross-platform, 2D Graphics library for .NET
https://sixlabors.com/products/imagesharp/
Other
7.41k stars 852 forks source link

Add option to decode bitmaps that do not have a file header #687

Closed MaryMajesty closed 2 months ago

MaryMajesty commented 6 years ago

Prerequisites

Description

There are cases when you need to decode BMP files that are provided without a bitmap file header, such as when decoding BMP files contained within an ICO file.

Suggestion

As the BitmapDecoderCore code itself notes, this file header gets parsed, but not actually used. As such it should be relatively simple to add an option to decode bitmaps without trying to parse the file header. This option would most likely have to be added to the Configuration class.

JimBobSquarePants commented 6 years ago

Wouldn't it be better to create a specific ICO decoder that then calls BitmapDecoder and adding a new SkipHeader option to IBmpDecoderOptions?

https://github.com/SixLabors/ImageSharp/blob/301c2cec662169bb330ac74c1bb44a9943885586/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs#L9

tocsoft commented 6 years ago

@JimBobSquarePants .ico files seem to be more of a container format not a codec in its own right... i would put it in the same category as tiff where it can have many separate image streams each with different sizes (thus not fitting in with our frames context) and each image stream can even be in different codecs (i.e. png and bmp encoded images).

Its something we should think about trying to find away of tackling at some point multi-image (not just multi-frame) containers.

antonfirsov commented 6 years ago

@TodesBrot is this an ICO-specific use case? Or do you know other cases where a BMP stream is provided without a header?

MaryMajesty commented 6 years ago

@antonfirsov As far as I know, BMP files that are loaded into memory do not have a file header either.

JimBobSquarePants commented 6 years ago

@antonfirsov @TodesBrot I'm happy to add this change to IBmpDecoderOptions.cs as the icon documentation I found clearly states that it only required the DIB BITMAPINFOHEADER.

https://msdn.microsoft.com/en-us/library/ms997538.aspx?f=255&MSPPError=-2147217396

@tocsoft On the case of an Icon format. It could simply be stored as a multi-frame image if we didn't have the height width restrictions on the frames.

springy76 commented 6 years ago

Why there is this difference multi-image and multi-frame? Is there any other picture format than GIF which is multi-frame in way that every frame has the same size at all? Or will ImageSharp support movies in the future?

If you look at WPF BitmapSource (which is just a wrapper for the WIC API) then they also use the term "Frame", but it doesn't have a restriction of with or height, so they support TIFF just out of the box.

And considering GIF: Even there every frame has its own width and height. But I don't remember if it was limited to delta-updates (building animations).

JimBobSquarePants commented 6 years ago

@springy76 As I recall we are treating each frame as such to make it easier and faster to clone frames. (It's been a while so I could be wrong).

In Gif we use the Left and Top properties specified in the Image Descriptor for each frame to draw the pixel data into the Image Fame essentially offsetting it against a blank canvas.

I wonder whether we should be capturing the Top Left values in the ImageFrame<TPixel> class and then only checking (Frame (Left + Width)) = Image Width and the same for height.

This would allow us to preserve enough information to allow encoding of Ico files and optimize our Gif encoder also to ignore the transparent pixels.

tocsoft commented 6 years ago

the main reason in my head why they need to be the same dimensions if due to resize operations... if you call resize on a multi frame images what is the expected outcome?... right now all frame are resized to the size provided and that works logically when all frames are the same source size so everything scales uniformly.

JimBobSquarePants commented 6 years ago

@tocsoft That was the other place; I recall now. Thanks!

I think with the additional properties we can/and should still treat Resize in the same way. In my mind it would be business as usual except at the encoder time where we only encode what we need.

springy76 commented 6 years ago

Hmm.. I can't remember having the need to resize an entire file but always only a specific frame of it.

BTW: For GIFs in addition to the left-top-width-height properties per frame there is also a disposal mode for each frame. And it gets really "funny" to separate truecolor GIFs from animations.

JimBobSquarePants commented 6 years ago

@springy76 What we mean regarding resize is that we calculate the interpolation weights once per image because we are confident we can apply the same scaling calculation across all frames since they have the same dimensions.

Yeah, we already handle the disposal mode well for both the decoder and encoder. We thankfully don't need to handle rendering the images, just ensuring that we match the spec when encoding/decoding. I would imagine truecolor gifs would be a case of encoding individual offset 256 color frames, setting the repeat count and delay fields.

Lakritzator commented 1 year ago

Hint: Ico files can contain the icon in multiple resolutions, e.g. 48x48 and 256x256 and different color depths. It's even possible that in one file there are a few BMP based images and a PNG (for 256x256).

I already have C# code to support the .ico format for Greenshot, some of it I didn't even push yet, it might make sense to migrate (and donate) that code to ImageSharp. There are some restrictions in the format, which might be hard to translate into ImageSharp (1 bit is xored into the destination, example is the I-beam cursor)

@JimBobSquarePants Before I start creating a PR, my time is limited due to my kid needing special needs so it might take a while (or not, depending), I'd like to know if you would like to have .ico read/write support in ImageSharp and/or if maybe someone else is already on it?

P.S. I might need to look into #1048 too... if 1 & 4 bit support isn't in the BMP code yet.

JimBobSquarePants commented 1 year ago

Hi @Lakritzator

That would be great if you could! Please let me know what you need from my end. I have the beginnings of a plan to support frames of different sizes.

P.S. We support 1-32 bit of encoding now in BMP files.

team-orangeBlue commented 5 months ago

@TodesBrot is this an ICO-specific use case? Or do you know other cases where a BMP stream is provided without a header?

The Wii U GamePad's/DRC firmware contains several blobs, of which one of them is named ERR_. That blob is..

The ERR_ blob contains a 854x516 RGBA image encoded using a color palette. 
The beginning of the blob contains a 1024 byte colormap (256 x 4 x 1 byte, for red, green, blue and alpha). Right after the palette (at offset 0x400) starts the pixel raster data. The pixels are saved row-major with 8 bit- per-pixel (because it uses a 8-bit colormap). Each row is padded with two bits of zero, so that the row length is a multiple of four (bmp does that too). 

Basically just a bmp file, stripped of all its enconding info.

ERR_.zip Have fun

JimBobSquarePants commented 2 months ago

ICO support is now part of the V4 codebase. We have the option to SkipFileHeader in the BmpDecoderOptions options but it is currently internal, I'm happy to expose that property if required though. @team-orangeBlue I'm assuming you'd like me to do that?

team-orangeBlue commented 2 months ago

ICO support is now part of the V4 codebase. We have the option to SkipFileHeader in the BmpDecoderOptions options but it is currently internal, I'm happy to expose that property if required though. @team-orangeBlue I'm assuming you'd like me to do that?

I honestly was scavenging the internet on ways to view bitmaps without header info (or in specific, view the images used by the wii u's drc). I gave up because there were no approaches that would let me view and edit such files on the fly. I did come across this issue, read a bit and contributed what I had that appeared to be relevant. I currently have no interest in and use for imagesharp.

JimBobSquarePants commented 2 months ago

@team-orangeBlue Thanks for the update, I think I shall still expose the property in both the decoder and encoder, so we have that case is covered.

EDIT. Actually, those file types are missing other critical information (width, height) so I will not attempt to decode them. I'm going to close this issue.

team-orangeBlue commented 2 months ago

EDIT. Actually, those file types are missing other critical information (width, height) so I will not attempt to decode them.

854x480 if you need them.

jcoolsen commented 2 months ago

So, did you end up exposing SkipFileHeader or did you drop it completely, @JimBobSquarePants ?

JimBobSquarePants commented 2 months ago

@jcoolsen the property exits in the V4 codebase but it’s internal. The use case described in the issue is already covered because in V4 we have ico and cur decoders and encoders.

jcoolsen commented 2 months ago

@jcoolsen the property exits in the V4 codebase but it’s internal. The use case described in the issue is already covered because in V4 we have ico and cur decoders and encoders.

Thanks for the clarification :-)