GDI+ DrawImage of a JPG with white background is not white - gdi+

I am displaying a JPG in a C++ CWnd window using GDI+. The JPG has a pure white background, 0xffffff, but when displayed using graphics.DrawImage, the background is off-white with a mix of pixel colors such as 0xfff7f7, 0xf7fff7, 0xf7f7f7. Below is the code, I have tried various settings such as CompositingMode, SmoothingMode, etc. The image is not scaled.
The weird thing is that the background color is different depending on other non-white content in the image. If I make a simple all white JPG, then it works, or even a mostly white with just some black text. Comparison of images are shown below.
CClientDC dc(this);
Gdiplus::Graphics graphics(dc);
Gdiplus::Bitmap* bmp = Gdiplus::Bitmap::FromFile( L"c:\\test.jpg" );
graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQuality);
//graphics.SetCompositingQuality(Gdiplus::CompositingQualityHighQuality);
graphics.SetCompositingQuality(Gdiplus::CompositingQualityDefault);
graphics.SetCompositingMode(Gdiplus::CompositingModeSourceCopy);
//graphics.SetSmoothingMode( Gdiplus::SmoothingMode::SmoothingModeDefault );
graphics.DrawImage(bmp, 0, 0, bmp->GetWidth(), bmp->GetHeight() );
Here I have text and some blending only on the left side of the image (no alphas, this is JPG) . Everything to the right is pure white. You can see the background is all grey.
Here I started removing the internal content (only on the left side). After a certain point the entire background starts displaying white. ???
It doesn't really matter which part of the image area I remove before it starts displaying white, as long as I remove a large portion of it. The same occurs for pngs.
Here is the original test.jpg image...

I am answering my question with the solution that I found. It seems that using graphics.DrawImage directly on the passed HDC has some issues in my case. If I use a memory DC for the initial drawing, then BitBlt it on the HDC, then it works.
I also had some problems with PNG and transparency. Using the solution below, I was able to solve this problem as well. My PNG was loaded from a stream using Bitmap::FromStream. The alpha channel was lost and I was trying different attempts using LockBits and re-creating the bitmap with PixelFormat32bppARGB, as well as Cloning. I was able to get something to work (after a lot of effort and extra code), but it still had the grey background problem that I asked here.
In my case, I have a known solid background color for the transparent areas. I used Bitmap.GetHBITMAP and passed the background color. The bitmap was then drawn on the memory DC first. Here I was able to solve both of my problems!
Gdiplus::Bitmap* bmp = Gdiplus::Bitmap::FromFile( L"c:\test.jpg" )
Gdiplus::Color backColor( 0xff, 0xff, 0xff );
HBITMAP hBmp;
bmp->GetHBITMAP( backColor, &hBmp );
CDC bitmapDC;
bitmapDC.CreateCompatibleDC(hdc); // pass original HDC for drawing
HBITMAP oldBmp = bitmapDC.SelectBitmap(hBitmap);
::BitBlt( hdc, x, y, cx, cy, bitmapDC.m_hDC, 0, 0, SRCCOPY );
bitmapDC.SelectBitmap(oldBmp);
DeleteObject( hBmp );
If anyone knows, I would be interested why this fixes the problem.

How did you confirm the JPG background is truly white? JPG implements compression that can vary the color of pixels. If there are mixed colors, then there can be certain types of blending and mixing that are part of that compression.
Can you show us the original image?

Related

Qt3D transparency in offscreen renderer

I'm using Qt3D with a combination of this offscreen renderer and modified the framegraph to include a background image, like here.
Unfortunately, adding transparency to the objects drawn over the background image using QPhongAlphaMaterial only works unsatisfactorily.
This is th result:
What you can't see here is that the whole circle part is actually transparent, i.e. the renderer wrote the transparency value of the object for the whole pixel instead of adding it transparently on top of the background.
This is what the rendered object looks like wihtout transparency:
And this is the background:
The framegraph has two branches: one for the backgroun image, which is processed first, and one for the objects. I added a QRenderStateSet for the objects that contains a QBlendEquation with the blend function set to add and a QBlendEquationArguments with source RGB and alpha set to 1, and destination RGB and alpha set to 1 minus source alpha.
Any ideas how to fix this problem?
(For anyone wondering, I took the images from the T-Less dataset and wrote a program to create ground-truth data for 6D pose estimation)
Similarly to this question, the format of the texture that is being rendered to needs to be set to RGB8_UNorm and not RGBA8_UNorm, i.e. without the alpha channel.

A-Frame Canvas texture default color white in VR-mode

I am applying a canvas as a texture to a plane. And it looks fine (The background is white by default) if I am displaying it within a browser itself.
But as I change to Virtual Reality Mode the background of the canvas is changing to black.
I know that i can place a white rect to have a white background, but this is not feasible due to performance issues.
Are there any other solutions to tackle this problems?
Thanks!
Try filling in the canvas as white (fillRect), or adding a background to the scene itself (<a-sky color="#FFF">). Let me know if that works, or provide a JSFiddle for us to play around.

Qt Qpixmap generates a blurry image

As part of a larger project i'm trying to draw basic shapes on a QPixmap but the generated image always appears blurry ie. the circle is not a pure red circle, the edges are blurred and the colour is not true red as expected. This becomes an issue later on with what I need the image for. Here's the relevant code snippet, i've played around with antialiasing options and render hints but i've not had any luck. Any help would be much appreciated!
QPixmap pixmap(QSize(300,300));
QPainter painter( &pixmap);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.fillRect( QRectF(0, 0, 300, 300),Qt::white);
painter.setPen(Qt::red);
painter.drawEllipse( QPoint(150,150), 75, 75);
painter.setPen(Qt::green);
QLineF line(30, 30, 30, 270);
painter.drawLine(line);
pixmap.save("test1.jpg", "jpg", 100);
I've been asked to include an image to show the issue, here's a close up of the image which shows the green line not being true green and the red circle not being true red and with blurred edges.
The problem that you have with the red color is that Qt by default uses chroma color subsampling (2x2 blocks) when saving to JPG format.
The only way to avoid this problem is using another format. Saving the same image with PNG format returns a pure red circle (255,0,0).
Regarding to the blurry circle, it occurs because of QPainter::Antialiasing RenderHint. In your case, not using any renderHints shows a sharp image. Below you can see your image with pure red color (PNG format) and sharp edges (not RenderHints). Take into account that the blurriest approach will be using QPainter::Antialiasing so avoid it if you are aiming to image sharpeness. Depending on your needs you could try QPainter::HighQualityAntialiasing RenderHint, but nothing else.

Transparent QGraphicsWebview over QGLWidget leads to super imposed images

I have a transparent QGraphicsWebview inside a QGraphicsView with the following settings:
The QGraphicsView is the high level widget, and is shown in full screen mode
The graphics view uses a QGLWidget as its view port (to use opengl-es)
Alpha channel and double buffering are enabled in this QGLWidget
Transparency is achieved by graphicsView->setStyleSheet("background:transparent")
Following attributes are set for QGraphicsView and QGraphicsWebview
WA_TranslucentBackground = true
WA_NoSystemBackground = true
WA_OpaquePaintEvent = false
The QPalette::Base and QPalette::Window brushes of webview and webview->page() are set to Qt::transparent
At the beginning, the transparency works fine. But as the screen get updated (when I scroll), it looks like the new bitmap is blended on top of the existing one to get a superimposed picture. After about 5-6 screen updates, this blending causes the colors to accumulate and form an opaque rectangle (with a corrupted image). Following images show first, second and final stages of the problem.
How do I tell qt/opengl to stop blending and just draw the new image to the frame buffer?
I tried calling fillRect(boundRect(), Qt::transparent) from overridden Webview::paint and GraphicsView::paintEvent; but it didn't work except for making the updates slower.
I am new to Qt and OpenGl, so I might be missing some basic flags or settings.
I tried all the methods mentioned above. They did not work for me. I then debugged into qtbase code and found that setting the Opacity level make the top browser layer transparent.
this->setOpacity(0.1);
this pointer points to the QGraphicsWebView object.
With this method, the whole front browser contents including background will be transparent. To separate header, paragraph and background and to specify different transparent levels for them, I will have to dig into webkit code a little further to figure out the problem. But for now, setOpacity() did the trick and is good enough for what I am doing.
It turns out the problem is graphicsView->setStyleSheet("background:transparent");. Who would have guessed?!
Yeah, the line that I thought made transparency work was actually causing troubles with transparency. The application works fine without that line (or if you change it to background:none)
In short, steps to get a transparent QGraphicsWebview using QGLWidget:
Set the Base palettes of QGraphicsWebview, QWebpage and the outer QGraphicsView to Qt::transparent
scene->setBackgroundBrush(QBrush(Qt::transparent));
You should also make sure that html body background is set to transparent values:
html, body {
background-color: rgba(127, 127, 0, 0.5);
}

Why does the file size of a png24-sprite increase when adding transparent white-space?

I am creating a png24 as sprite for css background images.
Due to padding issues I have to keep a certain amount of space between the icons in the sprite.
When doing so the file size of the png increases even though no information was added... Just empty, transparent space.
Is there any workaround for this? (I have already tried png compression - smushit - but no significant improvement made...)
Thanks
Empty, transparent space is information as well. If a PNG has an alpha channel, then every pixel consists of the informations (r,g,b,a) for red, green, blue and alpha components. In case of a transparent pixel the alpha is simply 0, but it's nevertheless information that is present in the file.
Empty is still kind of data, so when you add an empty space, you add a data that tells the PNG decoder about the empty space between each graphic.
I suppose the added file size is insignificant next to making extra requests to the server.

Resources