Determing the color of uncovered GIF pixels - gif

Here is a GIF containing just one image, 75 pixels wide.
The image has an Image Descriptor with an Image Left Position of 25.
So the leftmost 25 pixels of the image are not covered. Since the GIF specification states that
The Background Color is the color used for those pixels on the screen that are not covered by an image.
and the Background Color Index is 0, and the first entry in the palette is (0, 255, 0), I would think those leftmost 25 pixels should be green.
Instead, the browser renders those pixels as transparent.
Can anyone tell me why this is? Have I missed something in the specification?

I've managed to find https://legacy.imagemagick.org/Usage/anim_basics/#dispose. In discussing why ImageMagick uses transparency for disposal method 2, it states (emphasis mine)
There is some thinking that rather than clearing the overlaid area to the transparent color, this disposal should clear it to the 'background' color meta-data setting stored in the GIF animation. In fact the old "Netscape" browser (version 2 and 3), did exactly that. But then it also failed to implement the 'Previous' dispose method correctly.
On the other hand the initial canvas should also be set from the formats 'background' color too, and that is also not done. However all modern web browsers clear just the area that was last overlaid to transparency, as such this is now accepted practice, and what IM now follows.

Related

Interpretation of "background colour index" in GIF specification

If you look in the GIF specification and search for "Background Color Index", you see the following description:
vii) Background Color Index - Index into the Global Color Table for
the Background Color. The Background Color is the color used for those
pixels on the screen that are not covered by an image. If the Global
Color Table Flag is set to (zero), this field should be zero and
should be ignored.
There is an ambiguity here, which is that if the "Global Color Table Flag" is set to zero and this field is ignored, then it is undefined what background colour of a GIF actually should be if the image data itself does not cover the entire image area. This possible because every image data block specifies left/right/width/height independently and there is no requirement that every pixel must be encoded by the image data.
Am I misinterpreting this? If not, then in the presence of this ambiguity, what is the de facto behaviour of GIF implementations today?
The background color index is often ignored by decoders (including some modern browsers), whereas GDI+ (eg. Windows Paint or .NET WinForms controls) respect it. GDI+ handles it like this:
If there is no global palette, OR the first frame has transparency (the Transparent Color Flag is set in the Graphic Control Extension), then the background is transparent
If there is a global palette AND the first frame has no transparency (there is no Graphic Control Extension for the first frame, or the Transparent Color Flag is not set for it), then it means a color index from the global palette and is significant only if not the whole virtual screen area is covered by the first image, or when the "Restore to background color" disposal method is set for a frame. In latter case it does not matter if a possibly existing local palette does not contain the background color.
To demonstrate its effect I created a simple animation of two frames with my encoder, and then played with some settings (feel free to download the images and see their content in a file viewer because I added some textual hint in the files). You can use this app to see the animations in a Win32 app using GDI+ rendering.
Common properties:
All images have a global palette so the the background color can be set.
The background color is set to green.
The Virtual Screen Size is 64x64 pixels
The first frame is 48x48 pixels
The second frame is 32x32 pixels
The animation rendered by your browser
The 2nd frame by GDI+
Description
None of the frames are transparent, there is no clear.
Both frames are transparent, there is no clear.
Only the 2nd frame is transparent, there is a clear after the first frame.
For the example, Safari uses black as the background. With Win10 photo viewer it's hard to tell, as it uses a black background anyway. Chrome, IE and Edge use white.
The spec doesn't define the behaviour when there's no background colour and you need one, so I guess arbitrary choices is what you'll get, though I vote for transparent being the most sensible.
Yes, the ambiguity is indeed present. Background color is largely a derelict of GIF87a, currently only necessary for 'Restore Background' frame blending mode.
By now, all decoders I have seen treat pixels not belonging to any frame as transparent even if transparency flags in all of the frames are zeroed.
Consider this GIF, for example:
See how your browser interprets it? The whole background is transparent.
P.S.: in case it does not loop, reload the page using Ctrl+F5.

Chrome plugin window image inverted

We are working on a video player plugin with FireBreath. It has a windowless mode, and in Chrome on Windows it produces a very strange effect.
Whenever we try to paint in the hdc the pixels appear either in the right colour or inverted, depending of the value of the most significant bit in any of the 3 channels.
This means that in full colour depth on average half of the pixels appear inverted, while the other half is fine. It is the same both when displaying a video frame using StretchDIBits(), and when just filling with solid colours with FillRect(). The SetStretchBltMode() is set to COLORONCOLOR.
We could not find a solution so far, our temporary hack is to convert the colours to half the depth and set all the most significant bits to 1, but it's obviously a bad solution for the waste of CPU effort and losing half the colour depth.
Yeah, Chrome has a weird bug that way. The easiest fix is to set your background color to black behind the window; there is a whole thread on this on the firebreath-dev group.
EDIT: bug might actually not be the right term, on reflection; it has an interesting implementation that way =]

Defining how 2 separate, overlapping canvases blend

I basically want to put a canvas on top of another and define the way their contents are blended.
I have one white canvas with black characters on it, and I want to highlight a part of it with a transparent blue rectangle, without having my black characters in the background turning dark blue. In fact, I need the aspect I'd get if I merged the two canvases with globalCompositeOperation set to "multiply" instead of default, while keeping both canvases separated and overlapping.
Here's what I have :
Here's what I want :
I am aware that globalCompositeOperation would allow me to do that if I merged the two canvases into one. But I'd rather keep both canvases : my background canvas is displayed by a lib. I can still draw in it, but that would complicate things a lot:
I'd be too dependent on their logic and would have to tweak mine and theirs to make it work,
performance is critical and this solution would imply much more drawing at 24fps,
I'd struggle every time the lib is updated...
All in all it seems way better to keep away from interfering with the lib. Is there a way to choose how overlapping canvases will behave?
Thanks in advance!
EDIT: We've also thought of transforming the white parts of the background canvas into transparent parts and adding our highlight canvas underneath, but that's also complicated, if not impossible.
Do I understand that the letters canvas the lib draws has an opaque (white) background rather than a transparent one?
If so, any options for applying highlighting will be relatively poor in performance.
Standard canvas compositing won't help as there is no blending mode that combines source-destination pixels.
What you're left with is .getImageData to get the letters pixels. Then apply blue pixels where they overlap white pixels but not where they overlap black(letter) pixels.
However .getImageData is not GPU accelerated and is therefore relatively slow.
Putting the blue highlighting canvas behind a non-opaque letters canvas would give you the best performance.
Bottom line: If performance is critical and you want 24+ fps then hack that library to make the background transparent instead of opaque-white. (sorry!)

How do browsers detect GIF image sizes?

I was noticing that a GIF was being displayed with padding in FireFox 5 and IE 8. When I viewed the image size via FireBug, I noticed that it was a few pixels larger than expected.
Expected height: 160px vs. actual height: 171px
When I opened the GIF in an image editor, the editor displayed the correct dimensions, however when I ran ImageMagick identify I received the following information:
newGif.gif GIF 200x160 200x171+0+5 PseudoClass 256c 30kb
If I modified the geometry to 200x160+0+0 the image displayed as I expected it to in FireFox. FireFox and IE 8 seemed to be referencing the Image's page geometry rather than dimensions! Is my analysis correct and if so is this true for all image types or just GIF's?
Updated, I have included an image for your viewing pleasure! This image displays as 200 x 171 for me in FF, but is actually 200 x 160 when you download and view in a graphics program.
Header of this GIF file does not correspond to it's body.
Image dimensions are stored in 6th to 9th bytes and from the screen shot you can see that dimensions in the header are 00C8 x 00AB which is 200x171 but it's actual size is 200x160
So this image is not valid. There are no standardized behavior for parsing invalid gifs and that's why there is this inconsistency.
Most probably firefox preallocates place for images before they are fully downloaded, when an image is fully downloaded it is put into the center of preallocated space. and because preallocated space is 200x171 but the actual image is 200x160 you will see a border.
EDIT: After going through GIF format reference it appears that GIF does allow this. So the image is valid. So here's what's actually going on here:
GIF format consists from several blocks. There is a header block and one or more(if the image is animated) image blocks (there could be other blocks as well, but they are not connected with the issue). Header block holds some information about the image, including it's width and height. However each image block has it's own width and height as well. So what happens with the image in question that it has the main image size as 200x171 but the single frame with the size 200x160. So most editing programs and libraries which doesn't support animated gifs will extract the first frame and display it with the size 200x160 the browsers and editors which do support animation should display it with the full size of 200x171.
PS Every image block has image top and image left position. It seems that by allowing frames to be smaller than canvas, and allowing to move frame's position on the canvas, GIF's developers tried to shave couple of bytes of the animated gif files. I wonder if any of the modern graphic editors take advantage of that... probably not... :)
GIF format byte order
I suspect that the GIF is an animated format, so it could contain several images located on different positions of the geometry frame. Therefore, the browser should reserve place for a whole thing.
If you save the picture, and right click->properties, it'll state that it is 200x160, also of note when you preview the picture in windows black bars are added to the image, which is strange. If you open it in ms paint (just for demonstration purposes) you'll notice that the image is padded with black bars, and when you look at the file->properties it says the image is now 200x171.
The most likely scenario is that the file header says it's 200x160 (which windows/browsers etc looks at to tell you the image size quickly), while the actual image block is 200x171. The black bars don't show up in browsers as they are likely transparent, but as ms paint and windows preview don't support transparency, the black bars show in them. Further the correct size is found in mspaint because the header data is thrown out, and the properties show you properties of their data structure now holding the image block to image editing, similarly if you load the image into mspaint, modify the image to remove the black bars, save, and then put that picture into your browser then the padding will disappear.
Most of the time, when loading the image of an image file, only horizontal resolution of the image is required, and the image block is just read for the horizontal resolution for every vertical row of the image, when you read the end of the image block, you're at the end of the image, so heeding the vertical resolution isn't mandatory to load the image from it. This is why the image appears normal, and doesn't crop off the bottom edge.
As for why this image isn't padded in other browsers. I can only assume that this padding images with boarders is a standard of sorts that they have come to expect in image files, and when confronted with an image block larger than the file header specifies, they crop it toward the centre of the image block to the best of their ability

beginner questions about canvas elements with imported images... caching and changing colors

Couple noob questions about the canvas element in html. First, are images that are imported into a canvas element cached? Across browsers?
And second can I import a black and white png into a canvas element and then change the black color to a different color?
There is nothing in the canvas spec saying that images must be cached.
With a canvas, you need an Image HTML element already. The only way it can interact with a canvas is to call .drawImage() on the canvas' context.
There's no caching or saving after that event. The canvas prints the pixels of the image onto itself and then forgets that anything ever happened. No history, no caching.
You can easily draw (no importing) a black-and-transparent png onto a canvas, and then easily change the black color to a different color.
You would change the canvas context's globalCompositeOperation to be 'source-atop' and then fill the image space with the color of your choice.
You could do the same if it was black-and-white instead of black-and-transparent, but it would take more work.