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

 

ImageEn Forum
Profile    Join    Active Topics    Forum FAQ    Search this forumSearch
 All Forums
 ImageEn Library for Delphi, C++ and .Net
 ImageEn and IEvolution Support Forum
 TIEMultiBitmap (losing PNG transparency)

Note: You must be registered in order to post a reply.
To register, click here. Registration is FREE!

View 
UserName:
Password:
Format  Bold Italicized Underline  Align Left Centered Align Right  Horizontal Rule  Insert Hyperlink   Browse for an image to attach to your post Browse for a zip to attach to your post Insert Code  Insert Quote Insert List
   
Message 

 

Emoji
Smile [:)] Big Smile [:D] Cool [8D] Blush [:I]
Tongue [:P] Evil [):] Wink [;)] Black Eye [B)]
Frown [:(] Shocked [:0] Angry [:(!] Sleepy [|)]
Kisses [:X] Approve [^] Disapprove [V] Question [?]

 
Check here to subscribe to this topic.
   

T O P I C    R E V I E W
Fellafoo Posted - May 29 2022 : 07:43:27
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? }
8   L A T E S T    R E P L I E S    (Newest First)
xequte Posted - May 30 2022 : 19:19:51
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
Fellafoo Posted - May 30 2022 : 08:20:58
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.
Fellafoo Posted - May 30 2022 : 08:10:51
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;
Fellafoo Posted - May 30 2022 : 06:46:34
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.
xequte Posted - May 29 2022 : 16:14:47
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
Fellafoo Posted - May 29 2022 : 15:42:38
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.
xequte Posted - May 29 2022 : 14:18:02
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
Fellafoo Posted - May 29 2022 : 07:51:14
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.