jpegview icon indicating copy to clipboard operation
jpegview copied to clipboard

Display a checkerboard background in transparent images.

Open nephewtom opened this issue 3 years ago • 2 comments

Hello! 😊 JPEGview rocks! 💪 It is the fastest viewer I have seen on Windows, and I have tried a lot of them: W10 Photos, IrfanView, XnView, ImageGlass, etc.. I wonder if it would be possible to display a checkerboard background in transparent images.

For example, this transparent PNG image: redis-original

is shown in JPEGview: image

Paint.net shows it in this way: paint-net

Would it be possible to display a checkerboard background in transparent images like the one in Paint.net image? Best Regards. 🙏

nephewtom avatar Feb 23 '22 16:02 nephewtom

I'm not quite sure how to implement that change right now. Hopefully someone might direct me how to draw checkerboard instead of a single color on the canvas. But it's a nice suggested feature

sylikc avatar Mar 17 '22 17:03 sylikc

JPEGView's CJPEGImage class does not seem to support alpha. ImageLoadThread.cpp pre-blends alpha into the RGB pixels, creating an opaque. So alpha data is kind of 'lost', and there's no convenient way to just change the background painted in OnPaint() to checkerboard, and just paint the transparent image over it thereafter. Like so:

  • If CPEGImage can be enhanced to preserve alpha, create a custom checkerboard brush in lieu of backBrush used in CMainDlg::OnPaint() to paint the background.
//pseudo code
LRESULT CMainDlg::OnPaint(...
        ...
	CBrush backBrush;
	backBrush.CreateSolidBrush(CSettingsProvider::This().ColorBackground());
	CBrush hatchBrush;
	hatchBrush.CreateHatchBrush(HS_CROSS, RGB(255, 0, 0)); //red
        ...
		if (pDIBData != NULL) {
			CPoint ptDIBStart = HelpersGUI::DrawDIB32bppWithBlackBorders(...,
                            bViewTransparency? hatchBrush: backBrush, ...);
			...
		}

      //and change DrawDIB32bppWithBlackBorders to paint 1 big box for background instead of 4 border boxes.
      //though will screen flash badly with animated image?
  • See WebpAlphaBlendBackground(pixel, backgroundColor) and its use in ImageLoadThread.cpp .
    • JPEGView.ini has a setting TransparencyColor=0 0 0 for that backgroundColor. It appears to be in B G R format instead, not R G B as its comment says.
    • Alternatively, hack WebpAlphaBlendBackground to take in each pixel's x & y position, and based on the positions, alternately use checkerboard colours for backgroundColor.
      • Con: Won't be able to toggle checkerboard on and off while viewing though (without image reload), since the checkerboard is blended in once, upon image load.
static inline uint32 WebpAlphaBlendBackground(uint32 pixel, uint32 backgroundColor, bool bCheckerboard = false, int x = 0, int y = 0)
{
	uint32 alpha = pixel & 0xFF000000;

	if (alpha == 0xFF000000)
	{
		return pixel;
	}
	if (bCheckerboard)
	{
		//ignore configured backgroundColor, and use white and light gray for checkerboard
		if (((x & 0x10) && ((y & 0x10) == 0))
			|| ((y & 0x10) && ((x & 0x10) == 0)))
		{
			backgroundColor = 0x00ffffff;
		}
		else
		{
			backgroundColor = 0x00c0c0c0;
		}
	}
	if (alpha == 0) {
		return backgroundColor;
	}
	else {
		uint8 r = GetRValue(pixel);
		uint8 g = GetGValue(pixel);
		uint8 b = GetBValue(pixel);
		uint8 bg_r = GetRValue(backgroundColor);
		uint8 bg_g = GetGValue(backgroundColor);
		uint8 bg_b = GetBValue(backgroundColor);
		uint8 a = alpha >> 24;
		uint8 one_minus_a = 255 - a;

		return
			0xFF000000 +
			((uint8)(((r * a + bg_r * one_minus_a) / 255.0) + 0.5)) +
			((uint8)(((g * a + bg_g * one_minus_a) / 255.0) + 0.5) << 8) +
			((uint8)(((b * a + bg_b * one_minus_a) / 255.0) + 0.5) << 16);
	}
}

void CImageLoadThread::ProcessReadPNGRequest(CRequest* request) { //also change for ProcessReadWEBPRequest()
...
				//for (int i = 0; i < nWidth * nHeight; i++)
					//*pImage32++ = WebpAlphaBlendBackground(*pImage32, CSettingsProvider::This().ColorTransparency());
				for (int y = 0; y < nHeight; ++y)
					for (int x = 0; x < nWidth; ++x)
						*pImage32++ = WebpAlphaBlendBackground(*pImage32, CSettingsProvider::This().ColorTransparency(), true, x, y);
...

  • Incidental issue: Unable to save an image with transparency - or rather the transparency is lost. The output image will Not have transparency. Its background will be default black.

CJPEGView looks super complicated to change.

sdneon avatar Jan 15 '23 16:01 sdneon