ImageEn for Delphi and C++ Builder ImageEn for Delphi and C++ Builder

 

ImageEn Forum
Profile    Join    Active Topics    Forum FAQ    Search this forumSearch
Forum membership is Free!  Click Join to sign-up
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 ImageEn Library for Delphi, C++ and .Net
 ImageEn and IEvolution Support Forum
 Existing Display List: Replace call to StretchDIBits
 New Topic  Reply to Topic
Author Previous Topic Topic Next Topic  

Fellafoo

USA
44 Posts

Posted - Feb 28 2022 :  12:27:20  Show Profile  Reply
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

xequte

38191 Posts

Posted - Feb 28 2022 :  20:59:52  Show Profile  Reply
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
Go to Top of Page

Fellafoo

USA
44 Posts

Posted - Mar 03 2022 :  13:41:12  Show Profile  Reply
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?
Go to Top of Page

Fellafoo

USA
44 Posts

Posted - Mar 03 2022 :  17:27:02  Show Profile  Reply
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.
Go to Top of Page

xequte

38191 Posts

Posted - Mar 03 2022 :  20:38:38  Show Profile  Reply
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
Go to Top of Page

Fellafoo

USA
44 Posts

Posted - Mar 07 2022 :  09:35:11  Show Profile  Reply
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.


Go to Top of Page

xequte

38191 Posts

Posted - Mar 07 2022 :  21:42:38  Show Profile  Reply
Can you attach this source image.

(For testing. Not just because I love the Mazda MX5 RF).

Nigel
Xequte Software
www.imageen.com
Go to Top of Page

Fellafoo

USA
44 Posts

Posted - Mar 08 2022 :  09:02:33  Show Profile  Reply
Here are the two source files (Miata and Flag)



Go to Top of Page

xequte

38191 Posts

Posted - Mar 08 2022 :  15:04:07  Show Profile  Reply
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
Go to Top of Page

Fellafoo

USA
44 Posts

Posted - Apr 13 2022 :  11:32:46  Show Profile  Reply
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.
Go to Top of Page

xequte

38191 Posts

Posted - Apr 13 2022 :  16:12:55  Show Profile  Reply
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
Go to Top of Page

Fellafoo

USA
44 Posts

Posted - May 03 2022 :  06:52:31  Show Profile  Reply
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.

Go to Top of Page

xequte

38191 Posts

Posted - May 04 2022 :  00:36:23  Show Profile  Reply
Hi

Can you resend me the demo you mention in your email? I have not received it.

Nigel
Xequte Software
www.imageen.com
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
Jump To: