T O P I C R E V I E W |
Fellafoo |
Posted - Feb 28 2022 : 12:27:20 Hello,
I'm evaluating the ImageEn toolkit and this is my first post. I've been able to use MergeWithAlpha and RenderToCanvasWithAlpha to combine PNGs with a background image or canvas. However, I need to merge the images into a device context then BitBlt the result to the canvas.
Currently, when I'm adding bitmaps to the destination HDC, I call...
if (
StretchDIBits( { Number of Scanlines }
DestDC, { Destination }
WinPntsPartial[1].x, { Dest. (x) Left }
WinPntsPartial[2].y, { Dest. (y) Top }
dw, { Dest. Width }
-dh, { Dest. Height }
sx, { Src. (x) Left }
sy, { Src. (y) Top }
sw, { Src. Width }
sh, { Src. Height }
lpNewBits, { Image Bits }
BitmapHeader^, { Bitmap Info }
DIB_RGB_COLORS, { Color Table }
SRCCOPY) { Raster Operation Code }
> 0) then begin
Inc(NumVectorCount);
goto DoneSblt;
end;
This works with a DIB I create with ImageEn, but of course I lose the alpha-transparency.
ImageEnViewDst := TImageEnView.Create(nil);
ImageEnViewDst.IEBitmap.ParamsEnabled := True;
ImageEnViewDst.IO.LoadFromFile(ImgFName);
ImageEnViewDst.EnableAlphaChannel := True;
ImageEnViewDst.IEBitmap.AlphaChannel;
ImageEnViewDst.IEBitmap.Flip(fdVertical);
hDIBInfo := ImageEnViewDst.IO.IEBitmap.CreateDIB;
I'm at a loss as how to proceed and would appreciate any guidance to point me in the right direction.
Thank You,
MFM |
12 L A T E S T R E P L I E S (Newest First) |
xequte |
Posted - May 04 2022 : 00:36:23 Hi
Can you resend me the demo you mention in your email? I have not received it.
Nigel Xequte Software www.imageen.com
|
Fellafoo |
Posted - May 03 2022 : 06:52:31 I've come up with a work-around to the 'muddy' blending problem while using a mapping mode of MM_LOENGLISH (I also have the viewport origin set to the lower-left corner instead of the upper-left but I don't think that matters).
Here's the code I'm using for bitmaps with an alpha channel.
if (not Pipe.ToPlotter) then begin
GetClipBox(DestDC, ClipRect);
crTL := ClipRect.TopLeft;
crBR := ClipRect.BottomRight;
crWd := ClipRect.Right - ClipRect.Left;
crHt := ClipRect.Top - ClipRect.Bottom;
if (MemCnv.Handle <> DestDC) then ShowMessage('Canvas Handle Mismatch!');
if IsTransparent then begin
ieCnv := TIECanvas.Create(MemCnv);
SelClipRgn := SelectClipRgn(ieCnv.GDICanvas.Handle, Rgn);
Use_MM_LOENGLISH := False; //True;
if Use_MM_LOENGLISH then begin { Alpha Blend does not work properly with this mapping mode }
ieBmp.Flip(fdVertical); { Flip it }
//ieBmp.Resample(crWd, crHt);
//ieBmp.DrawToCanvasWithAlpha(ieCnv.GDICanvas, crTL.X, crBR.Y);
ieBmp.RenderToCanvasWithAlpha(ieCnv.GDICanvas, crTL.X, crBR.Y, crWd, crHt, sx, sy, sw, sh, 255, rfFastLinear, ielNormal, 1);
end
else begin
{ Use Pixels }
pxTL := crTL;
pxBR := crBR;
LPtoDP(DestDC, pxTL, 1); { Convert clipping rectangle to canvas pixels }
LPtoDP(DestDC, pxBR, 1);
pxWd := Abs(pxBR.X - pxTL.X);
pxHt := Abs(pxTL.Y - pxBR.Y);
SetMapMode(ieCnv.GDICanvas.Handle, MM_TEXT); { Change mapping mode to pixels }
SetViewPortOrgEx(ieCnv.GDICanvas.Handle, 0, 0, nil); { Set origin to upper-left corner }
//ieBmp.Resample(pxWd, pxHt);
//ieBmp.DrawToCanvasWithAlpha(ieCnv.GDICanvas, pxTL.X, pxTL.Y, 255, 1);
ieBmp.RenderToCanvasWithAlpha(ieCnv.GDICanvas, pxTL.X, pxTL.Y, pxWd, pxHt, 0, 0, ieBmp.Width, ieBmp.Height, 255, rfFastLinear, ielNormal, 1);
end;
ieCnv.Free;
end;
I'd still like to do this more directly as there must be a performance hit but at least it's working.
|
xequte |
Posted - Apr 13 2022 : 16:12:55 Hi
I'm not aware of any issues.
Are you able to create a simple demo that we can test here.
If it is only the edges you are concerned with, you might want to apply feathering:
https://www.imageen.com/help/TImageEnProc.FeatherAlphaEdges.html
Nigel Xequte Software www.imageen.com
|
Fellafoo |
Posted - Apr 13 2022 : 11:32:46 I can get the PNG file to merge with the canvas 'cleanly' by changing the mapping mode from MM_LOENGLISH to MM_HIGHENGLISH. Of course, this has the effect of drawing everything 10x smaller so I'm hoping this is not my only option.
When we create the device contexts for our Draw Form and corresponding Background (used for BitBlt), we set the mapping mode so each logical unit is 0.01", positive x is to the right, positive y is up and the origin is at the lower-left corner.
For example:
{ Draw Form Canvas }
DrawDC := GetDC(Self.Handle);
SetMapMode(DrawDC, MM_LOENGLISH);
SetViewPortOrgEx(DrawDC, 0, ClientHeight, nil);
{ Background Canvas }
bDC := CreateCompatibleDC(GetDC(0));
SetMapMode(bDC, MM_LOENGLISH);
SetViewPortOrgEx(bDC, 0, Self.ClientHeight, nil); We draw to bDC off screen in memory while building up the layered image. Then blit bDC into DrawDC at the end.
I'm hoping this is just a bug in the DrawToCanvasWithAlpha and RenderToCanvasWithAlpha routines that can be fixed. I tried calling Resample then DrawToCanvasWithAlpha but got the same result as calling RenderToCanvasWithAlpha. |
xequte |
Posted - Mar 08 2022 : 15:04:07 OK, so it looks like a rendering filter issue (image is drawn to canvas without a quality filter). Can you show me your code?
Nigel Xequte Software www.imageen.com
|
Fellafoo |
Posted - Mar 08 2022 : 09:02:33 Here are the two source files (Miata and Flag)
|
xequte |
Posted - Mar 07 2022 : 21:42:38 Can you attach this source image.
(For testing. Not just because I love the Mazda MX5 RF).
Nigel Xequte Software www.imageen.com
|
Fellafoo |
Posted - Mar 07 2022 : 09:35:11 I'm making some progress on this, thank you for your help. The merged image is 'muddy' in transparent areas. Not sure if I can address that with the RenderOperation. The source images are PNG files.
|
xequte |
Posted - Mar 03 2022 : 20:38:38 Hi
You should be able to it as follows:
// Draw a transparent PNG onto a canvas
var
bmp: TBitmap;
ieb: TIEBitmap;
aRect: TRect;
begin
bmp := TBitmap.Create;
ieb := TIEBitmap.Create;
try
bmp.LoadFromFile( 'D:\Background.bmp' );
ieb.Read( 'AlphaImage.png' );
if ieb.HasAlphaChannel( True ) = False then
raise Exception.create( 'Image has no alpha!' );
// Calculate destination rect so PNG is centered on our background image
aRect := GetImageRectWithinArea( ieb.Width, ieb.Height, Rect( 0, 0, bmp.Width, bmp.Height ));
ieb.RenderToCanvasWithAlpha( bmp.Canvas,
aRect.Left, aRect.Top, aRect.Right - aRect.Left, aRect.Bottom - aRect.Top,
0, 0, ieb.Width, ieb.Height,
255, rfFastLinear );
finally
bmp.Free;
ieb.Free;
end;
end;
Here is a demo: attach/xequte/202233203736_TransparentDraw.zip 899.61 KB
Nigel Xequte Software www.imageen.com
|
Fellafoo |
Posted - Mar 03 2022 : 17:27:02 Update...
As a test, I did the following.
cnv := TCanvas.Create; cnv.Handle := DestDC; ImageEnViewDst.IEBitmap.RenderToCanvasWithAlpha(cnv, WinPntsPartial[1].x, WinPntsPartial[2].y, dw, {-}dh, sx, sy, sw, sh, 128, rfNone, ielNormal, 1);
The image does get drawn to the screen in the correct position, but without the transparent background of the PNG file. |
Fellafoo |
Posted - Mar 03 2022 : 13:41:12 The application I'm working with is an 'MDI' CAD application. The 'BitBlast' was originally implemented for better display speed. There is also a display list that holds all the vector entities in memory. When a bitmap entity (a polyline with associated bitmap) is encountered, it is processed for clipping (its own boundary and the screen) before going to the Printer, ClipBoard, or Screen (i.e., the destination HDC).
At this point in the process the current bitmap is a handle to a DIB (hDIBInfo: THandle). A clipping region (HRGN) is set in the device context accordingly and the image is added using the StretchDIBits function. This is where the current entity/bitmap is being added to the 'built-up' display and where I need to merge it transparently.
At the end of the process, the device context is updated on the TCustomForm.Canvas using the BitBlt function. For testing purposes I'm loading the bitmap directly into a TImageEnView then assigning the local hDIBInfo to TImageEnView.IO.IEBitmap.CreateDIB;
{ Load source image directly into ImageEN }
ImageEnViewDst := TImageEnView.Create(nil);
ImageEnViewDst.IEBitmap.ParamsEnabled := True;
ImageEnViewDst.IO.LoadFromFile(ImgFName);
ImageEnViewDst.EnableAlphaChannel := True;
ImageEnViewDst.IEBitmap.AlphaChannel;
ImageEnViewDst.IEBitmap.Flip(fdVertical);
hDIBInfo := ImageEnViewDst.IO.IEBitmap.CreateDIB;
This seems to work fine with my existing code (except for the transparency). How can I add the DIB to the HDC transparently? |
xequte |
Posted - Feb 28 2022 : 20:59:52 Hi
I would need to learn more of your requirements (e.g. see your old code), but I would suggest the following:
- You can use a TBitmap as an intermediary by just assigning a TIEBitmap to it, e.g. ieb.CopyToTBitmap();
https://www.imageen.com/help/TIEBitmap.CopyToTBitmap.html
- Or using the TIEBitmap.VclBitmap property:
https://www.imageen.com/help/TIEBitmap.VclBitmap.html
- Instead of BitBlt'ing to a canvas why not just use DrawToCanvas or RenderToCanvas:
https://www.imageen.com/help/TIEBitmap.DrawToCanvas.html
Nigel Xequte Software www.imageen.com
|
|
|