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
 TIEMultiBitmap (losing PNG transparency)
 New Topic  Reply to Topic
Author Previous Topic Topic Next Topic  

Fellafoo

USA
52 Posts

Posted - May 29 2022 :  07:43:27  Show Profile  Reply
How do I maintain transparency when appending an image to a TIEMultiBitmap? I'm intending to hold all of the bitmaps that have been displayed previously in memory so they can be recalled as needed.

I've tried a few different approaches, but HasAlphaChannel returns False in every case.

      if (ieMultiBmp.Count <> 0) then begin
        for i := 0 to ieMultiBmp.Count - 1 do begin
          if ImgFName = ieMultiBmp.ImageFilename[i] then begin { GetHash? }
            ieBmp := ieMultiBmp.GetTIEBitmap(i);
            ieIdx := i;
          end
          else begin
            //ieBmp := TIEBitmap.Create(ImgFName);
            //ieMultiBmp.AppendImage(ieBmp);
            //ieMultiBmp.Read(ImgFname);
            //ieBmp.Free;
            ieMultiBmp.AppendImage(ImgFname);
            ieBmp := ieMultiBmp.GetTIEBitmap(ieMultiBmp.Count - 1);
            ieIdx := ieMultiBmp.Count - 1;
          end;
        end;
      end
      else begin
        //ieBmp := TIEBitmap.Create(ImgFName);
        //ieMultiBmp.AppendImage(ieBmp);
        //ieMultiBmp.Read(ImgFName);
        //ieBmp.Free;
        ieMultiBmp.AppendImage(ImgFname);
        ieBmp := ieMultiBmp.GetTIEBitmap(ieMultiBmp.Count - 1);
        ieIdx := ieMultiBmp.Count - 1;
      end;

      //ieBmp := TIEBitmap.Create(ImgFName);
      //ieBmp.Read(ImgFName);
      IsTransparent := ieBmp.HasAlphaChannel(True); { Validate - Is Alpha Channel Used? }

Fellafoo

USA
52 Posts

Posted - May 29 2022 :  07:51:14  Show Profile  Reply
Doh! I was using the wrong test files. So, the transparency works. However, I need some recommendations as this method is slower than reading the file from disk each time.
Go to Top of Page

xequte

38610 Posts

Posted - May 29 2022 :  14:18:02  Show Profile  Reply
Hi

You should be able to use:

// Check whether the image at an index has an alpha channel
info := ImageEnMView1.IEMBitmap.GetImageInfo( idx ); 
if info <> nil then
  hasAlpha := info^.HasAlphaChannel;


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

Fellafoo

USA
52 Posts

Posted - May 29 2022 :  15:42:38  Show Profile  Reply
Thanks Nigel. Can I use TIEMultiBitmap without TImageEnMView? My first attempt is crashing with an out of memory error when I add more than one bitmap at a time.
Go to Top of Page

xequte

38610 Posts

Posted - May 29 2022 :  16:14:47  Show Profile  Reply
Hi

Yes, you can, but TIEMultiBitmap doesn't have some of the loading features. Can you show me the TIEMultiBitmap code that is giving you problems?

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

Fellafoo

USA
52 Posts

Posted - May 30 2022 :  06:46:34  Show Profile  Reply
Here's the gist...


implementation

uses
  ...

const
  ieVisionEmail: String = '...@datacad.com';
  ieVisionSN: String = 'ievis-xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx';

var
  ieMultiBmp: TIEMultiBitmap;

procedure InitIEVision;
var
  ErrMsg: String;
  ieGlobalSettings: TIEGlobalSettings;

begin
  //IEVisionSetSerialNumber(ieVisionEmail, ieVisionSN);
  ieGlobalSettings := TIEGlobalSettings.Create(Application);
  //ieGlobalSettings.RegisterPlugIns(); { Register all available plug-ins }
  ieGlobalSettings.RegisterPlugIns([], ieVisionEmail, ieVisionSN); { Register all available plug-ins (IEVision User)}
  //ieGlobalSettings.RegisterPlugIns([iepiIEVision], ieVisionEmail, ieVisionSN); { Register only IEVision}
  //ieGlobalSettings.RegisterPlugIns([iepiPDFium]); { Register PDFium plug-in}
  if not (iepiPDFium in ieGlobalSettings.ActivePlugIns) then
    // Error
  //ieGlobalSettings.RegisterPlugIns([iepiLanguages]);
  if not (iepiLanguages in ieGlobalSettings.ActivePlugIns) then
    // Error
  else
    ieGlobalSettings.MsgLanguage := msSystem;

  ieGlobalSettings.Free;
  //if not IEVisionAvailable() then begin
  if not (iepiIEVision in ieGlobalSettings.ActivePlugIns) then begin
    //ShowMessage( 'This application requires the ievision.dll plug-in, v' + IEVC_EXPECTED_LIBRARY_VERSION +'.' );
    { Cannot use ShowMessage at this point in the application startup process! }
    ErrMsg := 'This application requires the ievision.dll plug-in, v' + IEVC_EXPECTED_LIBRARY_VERSION +'.';
    Windows.MessageBox(0, PChar(ErrMsg), 'GUI Error', MB_SYSTEMMODAL or MB_SETFOREGROUND or MB_TOPMOST or MB_ICONHAND);
  end;
end;

procedure CreateMultiBitmap;
begin
  ieMultiBmp := TIEMultiBitmap.Create();
end;

procedure DestroyMultiBitmap;
begin
  FreeAndNil(ieMultiBmp);
end;

procedure BitmapRegionIE(var DestDC: HDC; ImgFName: String; BmpFixedAspect: Boolean; Ang: aFloat; EntSize: uDgType.Point;
   Pipe: Pipe_Type; aBmpLocation: TBmpLocation; BmpBoundary: TGPC_Polygon);

const
  debug = False;

label
  DoneSblt, Exit_MemFree, Exit_Select_Null_ClipRgn;

var
  fdelta, ftop, fbot, ftopconst: aFloat;
  nSrcHeight: Integer;
  BmpPos: TMax2tpoints;
  dx, dy, dw, dh, { Destination parameters }
  sx, sy, sw, sh: Integer; { Source parameters }
  WinPntsFull, WinPntsPartial: TMax2tpoints;
  BmpBackClr: LongInt;
  Rgn: HRGN;
  br: HBRUSH;
  SelClipRgn: Integer; { for return value }
  vMin, vMax: TGPC_vertex;

  ieBmp: TIEBitmap; { ImageEN }
  ieCnv: TIECanvas; { Temporary canvas for ImageEN / Alpha }

  Go, IsTransparent, Use_MM_LOENGLISH: Boolean;

  TmpCnv: TCanvas; { For Printer }

  ClipBox: TRect; { Extents of clipping region }
  crTL, crBR, crTR, crBL: TPoint;
  crWd, crHt: Integer;
  pxTL, pxBR: TPoint;
  pxWd, pxHt: Integer;

  ImageID: Integer;
  PDF_ImgTop, PDF_ImgLeft, PDF_ImgWidth, PDF_ImgHeight: Double;
  RetVal: Integer;

  BitmapStream: TStream;
  i, ieIdx: Integer;

  ieMultiBmp: TIEMultiBitmap;

  function MakeBmpRegion: HRGN;
  begin
    if (BmpBoundary.NumContours = 0) then begin
      Result := 0;
      Exit;
    end;
    BeginPath(DestDC);
    BmpBoundary.DL_Clip_Draw(Pipe, False, False, True, True, 1{, brClr, brOpa, BmpBrush});
    EndPath(DestDC);
    Result := PathToRegion(DestDC);
  end;

  function GetWindowPoint(pt: uDgType.Point): TPoint;
  begin
    if Pipe.ToPlotter then begin
      Result.x := Round(pt.y);
      Result.y := Round(pt.x);
    end
    else if (DCClipBoard.IsOpen) then begin
      Result := DCClipBoard.ProcessPt(pt);
    end
    else begin
      Result.x := MyRound(pt.x * CurrXfrm.xSc + CurrXfrm.xOff); { -32768 to 32767 }
      Result.y := MyRound(pt.y * CurrXfrm.ySc + CurrXfrm.yOff); { -32768 to 32767 }
    end;
  end;

begin { BitmapRegionIE }
  if Pipe.ToPlotter and Assigned(PrinterPDF) then begin
    PrinterPDF.SaveState; { Save current clipping path (there should be none at this point). }
  end;

  Rgn := MakeBmpRegion;
  if (Rgn = 0) then begin
    Exit;
  end;

  if Pipe.ToPlotter or Pipe.ToClipboard then BmpBackClr := clWhite
  else BmpBackClr := DrawFormColor;
  (*
  { Load source image directly into ImageEN }
  if FileExists(ImgFName) then begin
    try
      Go := True;
      IsTransparent := False;
      ieBmp := TIEBitmap.Create;
      ieBmp.Read(ImgFName);
      IsTransparent := ieBmp.HasAlphaChannel(True); { Validate - Is Alpha Channel Used? }
    except
      Go := False;
      ieBmp.Free;
    end;
  end
  else begin
    Go := False;
  end;
  *)
  Go := True;
  { ieMultiBmp created during initialization }
  if (ieMultiBmp.Count > 0) then begin
    for i := 0 to ieMultiBmp.Count - 1 do begin
      if ImgFName = ieMultiBmp.ImageFilename[i] then begin { GetHash? }
        ieBmp := ieMultiBmp.GetTIEBitmap(i);
        ieIdx := i;
      end
      else begin
      	if FileExists(ImgFName) then begin
          ieMultiBmp.AppendImage(ImgFname);
          ieBmp := ieMultiBmp.GetTIEBitmap(ieMultiBmp.Count - 1);
          ieIdx := ieMultiBmp.Count - 1;
        end
        else begin
    	    Go := False;
        end;
      end;
    end;
  end
  else begin
  	if FileExists(ImgFName) then begin
      ieMultiBmp.AppendImage(ImgFname);
      ieBmp := ieMultiBmp.GetTIEBitmap(ieMultiBmp.Count - 1);
      ieIdx := ieMultiBmp.Count - 1;
    end
    else begin
    	Go := False;
    end;
  end;

  if not Go then
    goto Exit_Select_Null_ClipRgn; { Nothing to display - unable to get image }

  IsTransparent := ieBmp.HasAlphaChannel(True); { Validate - Is Alpha Channel Used? }  

  if not UpdateBitmapForAspectRatioIE(ieBmp, EntSize, BmpFixedAspect) then
    goto Exit_Select_Null_ClipRgn; { Nothing to display }

  if (Ang <> 0) and (not RotateBitmapIE(ieBmp, Ang, BmpBackClr)) then
    goto Exit_Select_Null_ClipRgn; { Nothing to display }

  if BmpFixedAspect then
    CheckUpdateAspectRatioIE(ieBmp, aBmpLocation);

  BmpBoundary.GetClipMinMax(vMin, vMax);
  aBmpLocation.ClipMin := BmpBoundary.MakePoint(vMin, 0);
  aBmpLocation.ClipMax := BmpBoundary.MakePoint(vMax, 0);

  if not CalcDisplayBitmapSizeIE(ieBmp, aBmpLocation, BmpPos) then
    goto Exit_Select_Null_ClipRgn; { Nothing to display }

  if not GetPartialBitmapIE(ieBmp, BmpPos[1], BmpPos[2], Pipe.ToPlotter) then
    goto Exit_Select_Null_ClipRgn; { Nothing to display }

  WinPntsFull[1] := GetWindowPoint(aBmpLocation.NoClipMin);
  WinPntsFull[2] := GetWindowPoint(aBmpLocation.NoClipMax);
  WinPntsPartial[1] := GetWindowPoint(aBmpLocation.ClipMin);
  WinPntsPartial[2] := GetWindowPoint(aBmpLocation.ClipMax);

  if Pipe.ToPlotter and (not RotateBitmapIE(ieBmp, cPi32, BmpBackClr)) then
    goto Exit_Select_Null_ClipRgn; { Nothing to display }

  if (DCClipBoard.IsOpen) and (not DCClipBoard.CurrentlyDrawing) then begin
    goto Exit_Select_Null_ClipRgn;
  end;

  if (not Pipe.ToPlotter) and Pipe.ChkBrk then begin
    Pipe.Brk := BrkPrss;
    if (Pipe.Brk = -1) then goto Exit_Select_Null_ClipRgn;
  end;

  if not Pipe.ToPlotter and not IsTransparent then ieBmp.Flip(fdVertical); { Flip it }

  BmpPos[1].x := 0;
  BmpPos[1].y := 0;
  BmpPos[2].x := ieBmp.Width;
  BmpPos[2].y := ieBmp.Height;

  sx := BmpPos[1].x;
  sy := BmpPos[1].y;
  sw := BmpPos[2].x;
  sh := BmpPos[2].y;
  dx := WinPntsPartial[1].x;
  dw := (WinPntsPartial[2].x - WinPntsPartial[1].x) + 1;
  dh := (WinPntsPartial[2].y - WinPntsPartial[1].y) + 1;

  { The SelectClipRgn function selects a region as the current clipping region for the specified device context. }
  SelClipRgn := SelectClipRgn(DestDC, Rgn);
  SelClipRgn := SelectClipRgn(MemCnv.Handle, Rgn);

  GetClipBox(DestDC, ClipBox);
  crTL := ClipBox.TopLeft;
  crBR := ClipBox.BottomRight;
  crTR.X := ClipBox.Right;
  crTR.Y := ClipBox.Top;
  crBL.X := ClipBox.Left;
  crBL.Y := ClipBox.Bottom;
  crWd := ClipBox.Right - ClipBox.Left;
  crHt := ClipBox.Top - ClipBox.Bottom;

  PDF_ImgLeft := crTL.X / 600;
  PDF_ImgTop := crTL.Y / 600;
  PDF_ImgHeight := Abs(crWd / 600);
  PDF_ImgWidth := Abs(crHt / 600);

  if (not Pipe.ToPlotter) then begin
    if IsTransparent then begin
      if ShowMemFrm then begin
        ieCnv := TIECanvas.Create(MemFrm.Canvas);
        SelClipRgn := SelectClipRgn(ieCnv.GDICanvas.Handle, Rgn);
      end
      else begin
        ieCnv := TIECanvas.Create(MemCnv);
      end;

      Use_MM_LOENGLISH := False;
      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);
      end
      else begin
        { Use Pixels }
        pxTL := crTL;
        pxBR := crBR;

        LPtoDP(DestDC, pxTL, 1);
        LPtoDP(DestDC, pxBR, 1);

        pxWd := Abs(pxBR.X - pxTL.X);
        pxHt := Abs(pxTL.Y - pxBR.Y);

        if not ShowMemFrm then begin
          SetMapMode(ieCnv.GDICanvas.Handle, MM_TEXT);
          SetViewPortOrgEx(ieCnv.GDICanvas.Handle, 0, 0, nil);
        end;

        { Resize AND Draw }
        ieBmp.RenderToCanvasWithAlpha(ieCnv.GDICanvas, pxTL.X, pxTL.Y, pxWd, pxHt, 0, 0, ieBmp.Width, ieBmp.Height, 255, rfFastLinear, ielNormal, 1);
      end;
      ieCnv.Free;
    end { if IsTransparent }
    else begin
      { Resize AND Draw }
      ieBmp.RenderToCanvas(MemCnv, crTL.X, crBR.Y, crWd, crHt, rfFastLinear, 0, DrawFormColor, True);
    end;

    Inc(NumVectorCount);
    goto DoneSblt;
  end; { not Pipe.ToPlotter }

  TmpCnv := TCanvas.Create;
  TmpCnv.Handle := DestDC; { Should be Printer or Metafile Preview }

  { Bitmap should not have been resized at this point... }
  if DCADPrinter.CreatingPreview then begin
    ieBmp.RenderToCanvas(TmpCnv, ClipBox, rfNone, 0, clWhite{DrawFormColor}, True);
  end
  else begin
    ieBmp.Resample(ClipBox.Right - ClipBox.Left, ClipBox.Bottom - ClipBox.Top);
    if IsTransparent then ieBmp.DrawToCanvasWithAlpha(TmpCnv, ClipBox.Left, ClipBox.Top)
    else ieBmp.DrawToCanvas(TmpCnv, ClipBox.Left, ClipBox.Top);
  end;

  if Assigned(PrinterPDF) then begin
    BitmapStream := TMemoryStream.Create;
    if IsTransparent then ieBmp.Write(BitmapStream, ioPNG, nil)
    else ieBmp.Write(BitmapStream, ioJPEG, nil);
    ImageID := PrinterPDF.AddImageFromStream(BitmapStream, 6);
    BitmapStream.Free;

    if (ImageID <> 0) then begin
      PrinterPDF.SelectImage(ImageID);
      PrinterPDF.DrawImage(PDF_ImgLeft, PDF_ImgTop, PDF_ImgHeight, PDF_ImgWidth);
    end;
    PrinterPDF.LoadState; { Restore clipping path (there should be none after this point). }
  end;

  TmpCnv.Free;

DoneSblt:
  if (not Pipe.ToPlotter) and (not Pipe.ToClipboard) then MyBitBlast;

Exit_MemFree:
  //ieBmp.Free;
  ieMultiBmp.ReleaseBitmap(ieIdx, False);

Exit_Select_Null_ClipRgn:
  SelectClipRgn(DestDC, 0);
  if (Rgn <> 0) then DeleteObject(Rgn);
end; { BitmapRegionIE }

initialization
  InitIEVision;
  CreateMultiBitmap;

finalization;
  DestroyMultiBitmap;

end.
Go to Top of Page

Fellafoo

USA
52 Posts

Posted - May 30 2022 :  08:10:51  Show Profile  Reply
I found and corrected a logic error that was causing duplicate images to be added to my MultiBitmap. Here's the corrected code;

  Go := True;
  { ieMultiBmp created during initialization }
  if (ieMultiBmp.Count > 0) then begin
    Found := False;
    for i := 0 to ieMultiBmp.Count - 1 do begin
      if (AnsiCompareText(ImgFName, ieMultiBmp.ImageFilename[i]) = 0) then begin { GetHash? }
        ieBmp := ieMultiBmp.GetTIEBitmap(i);
        ieIdx := i;
        Write2StartupLog('MultiBmp[' + IntToStr(ieIdx) + ']: ' + ImgFName);
        Found := True;
      end
    end;
    if not Found then begin
      if FileExists(ImgFName) then begin
        ieMultiBmp.AppendImage(ImgFname);
        ieBmp := ieMultiBmp.GetTIEBitmap(ieMultiBmp.Count - 1);
        ieIdx := ieMultiBmp.Count - 1;
        Write2StartupLog('MultiBmp[' + IntToStr(ieIdx) + ']: ' + ImgFName);
      end
      else begin
        Go := False;
      end;
    end;
  end
  else begin
    if FileExists(ImgFName) then begin
      ieMultiBmp.AppendImage(ImgFname);
      ieBmp := ieMultiBmp.GetTIEBitmap(ieMultiBmp.Count - 1);
      ieIdx := ieMultiBmp.Count - 1;
      Write2StartupLog('MultiBmp[' + IntToStr(ieIdx) + ']: ' + ImgFName);
    end
    else begin
      Go := False;
    end;
  end;
Go to Top of Page

Fellafoo

USA
52 Posts

Posted - May 30 2022 :  08:20:58  Show Profile  Reply
So, a quick test in DEBUG mode reveals that using the MultiBitmap results in a refresh time of 4.5 sec. vs. 14 sec. loading the files from disk everytime. The compiled exe time is 4.3 vs 4.5 sec.
Go to Top of Page

xequte

38610 Posts

Posted - May 30 2022 :  19:19:51  Show Profile  Reply
Sorry, are you able to create a simple demo that reproduces the error. This one has too much extraneous code to reasonably debug.

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