ImageSharp icon indicating copy to clipboard operation
ImageSharp copied to clipboard

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

Open MaryMajesty opened this issue 6 years ago • 14 comments

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 and RELEASE 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.

MaryMajesty avatar Aug 29 '18 19:08 MaryMajesty

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 avatar Aug 30 '18 06:08 JimBobSquarePants

@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.

tocsoft avatar Aug 30 '18 08:08 tocsoft

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

antonfirsov avatar Aug 30 '18 11:08 antonfirsov

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

MaryMajesty avatar Aug 30 '18 11:08 MaryMajesty

@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.

JimBobSquarePants avatar Aug 31 '18 09:08 JimBobSquarePants

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 avatar Sep 03 '18 08:09 springy76

@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.

JimBobSquarePants avatar Sep 03 '18 15:09 JimBobSquarePants

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 avatar Sep 03 '18 15:09 tocsoft

@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.

JimBobSquarePants avatar Sep 03 '18 16:09 JimBobSquarePants

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 avatar Sep 04 '18 07:09 springy76

@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.

JimBobSquarePants avatar Sep 06 '18 22:09 JimBobSquarePants

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.

Lakritzator avatar Mar 06 '23 09:03 Lakritzator

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.

JimBobSquarePants avatar Mar 06 '23 09:03 JimBobSquarePants