ImageSharp
ImageSharp copied to clipboard
Add option to decode bitmaps that do not have a file header
Prerequisites
- [X] I have written a descriptive issue title
- [X] I have verified that I am running the latest version of ImageSharp
- [X] I have verified if the problem exist in both
DEBUG
andRELEASE
mode - [X] I have searched open and closed issues to ensure it has not already been reported
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.
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
@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.
@TodesBrot is this an ICO-specific use case? Or do you know other cases where a BMP stream is provided without a header?
@antonfirsov As far as I know, BMP files that are loaded into memory do not have a file header either.
@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.
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).
@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.
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.
@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.
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.
@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.
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.
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.