Bitmap stream to PDF content area

PDF-XChange Editor SDK for Developers

Moderators: TrackerSupp-Daniel, Tracker Support, Paul - Tracker Supp, Vasyl-Tracker Dev Team, Chris - Tracker Supp, Sean - Tracker, Ivan - Tracker Software, Tracker Supp-Stefan

Forum rules
DO NOT post your license/serial key, or your activation code - these forums, and all posts within, are public and we will be forced to immediately deactivate your license.

When experiencing some errors, use the IAUX_Inst::FormatHRESULT method to see their description and include it in your post along with the error code.
Post Reply
dkeith2
User
Posts: 46
Joined: Mon Aug 14, 2017 8:28 pm

Bitmap stream to PDF content area

Post by dkeith2 »

I've created a signature pad for users to sign their name. Once the signature is obtained, I put the bitmap of the signature into a stream.

I need to do one or more of the following:
  • Convert stream to image, place in signature box
    Convert stream to image, place in form text field
    Convert stream to image, place in text box
    Convert stream to image, place on button
    Convert stream to image, place in any object that can be used as a bounding box
Here's one of my (feeble) attempts to get this to work:

Code: Select all

var
  page: IPXC_Page;
  pgTxt: IPXC_PageText;
  opts: IPXC_GetPageTextOptions;
  idx: Cardinal;
  txtInfo: IPXC_TextBlockInfo;
  arect: PXC_RectF;
  bmp: Vcl.Graphics.TBitmap;
  sigPad: TfrmSignaturePad;
  strmAdpt: TStreamAdapter;
  img: IPXC_Image;
  dHandle: DWORD;
begin
  // pdf form field editor class instance
  FFields := TPDFFormFieldEditor.Create(Self);
  Inst.Doc[0].CoreDoc.Pages.Get_Item(0,page);
  if Assigned(Page) then
  begin
    if page.GetText(opts,true,pgTxt) = S_OK then
      if pgTxt.Get_BlockInfo(idx,txtInfo) = S_OK then
        if txtInfo.Get_BBox(arect) = S_OK then
        begin
          sigPad := TfrmSignaturePad.Create(Nil);
          if sigPad.ShowModal = mrOk then
          begin
            bmp := Vcl.Graphics.TBitmap.Create;
            bmp.Assign(sigPad.SignatureImg);
            if bmp.HandleAllocated then
              dHandle := DWORD(bmp.Handle);
            // now what??? get the image into some kind of... IPXC_Image???
            if img.Get_Handle(dHandle) = S_OK then // img is null, so errors out here...
I've tried many things, all of which require hours of searching the interface code, none of which are intuitive. Can you please point me to some examples on how to do this?

Thank you.
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: Bitmap stream to PDF content area

Post by Sasha - Tracker Dev Team »

Hello dkeith2,

Please use forum search - many of questions are already been answered:
https://www.pdf-xchange.com/forum3 ... 50#p101050

Cheers,
Alex
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
dkeith2
User
Posts: 46
Joined: Mon Aug 14, 2017 8:28 pm

Re: Bitmap stream to PDF content area

Post by dkeith2 »

Based on the provided link, here's my current iteration, which does not work:

Code: Select all

var
  iPage: IPXC_Page;
  icPage: IIXC_Page;
  i: Integer;
  iContent: IPXC_Content;
  iItems: IPXC_ContentItems;
  iItem: IPXC_ContentItem;
  iImage: IPXC_Image;
  iType: TOleEnum;
  cnt,uHB,iHandle: Cardinal;
  beditable: WordBool;
  bmp: Vcl.Graphics.TBitmap;
  sigPad: TfrmSignaturePad;
  iCoreDoc: IPXC_Document;
  tgrSrc,tgrDest: tagRECT;
  pxrSrc: PXC_Rect;
begin
  sigPad := TfrmSignaturePad.Create(Nil);
  try
    if sigPad.ShowModal = mrOk then
    begin
      bmp := Vcl.Graphics.TBitmap.Create;
      bmp.LoadFromStream(sigPad.ImageStream);
      uHB := bmp.Handle;
    end;
    if FPDFEdit.Doc.CoreDoc.Pages.Get_Item(0,iPage) = S_OK then
      if iPage.GetContent(CAccessMode_WeakClone,iContent) = S_OK then
        if iContent.Get_Items(iItems) = S_OK then
          if iItems.Get_Count(cnt) = S_OK then
            for i := 0 to Pred(cnt) do
              if iItems.GetItemForEditing(i,iItem) = S_OK then
                if iItem.Get_type_(iType) = S_OK then
                  if (iType = CIT_Image) or (iType = CIT_InlineImage) then
                    if (iItem.Image_CreateIXCPage(False, 0, icPage) = S_OK) and Assigned(icPage) then
                    begin
                      iCoreDoc := FPDFEdit.Doc.CoreDoc;
                      if Assigned(iCoreDoc) then
                        if iPage.Get_Document(iCoreDoc) = S_OK then
                        begin
                          iImage := FPDFEdit.Doc.CoreDoc.AddImageFromIXCPage(icPage,1);
                          if Assigned(iImage) then
                          begin
                            iHandle := bmp.Canvas.Handle;
                            tgrSrc.left := 0;
                            tgrSrc.Top := 0;
                            tgrSrc.right := bmp.Width;
                            tgrSrc.bottom := bmp.Height;
                            if iItem.Get_BBox(pxrSrc) = S_OK then
                            begin
                              tgrDest.Left := Trunc(pxrSrc.left);
                              tgrDest.right := Trunc(pxrSrc.right);
                              tgrDest.top := Trunc(pxrSrc.top);
                              tgrDest.bottom := Trunc(pxrSrc.bottom);
                              if icPage.StretchDraw(iHandle,tgrDest,tgrSrc,ScaleMethod_Bilinear,2051) = S_OK then
                                  ;
                            end;
                          end;
                        end;
  finally
    sigPad.Free;
    bmp.Free;
  end;
end;
What I'm trying to do is take an existing pdf acroform with fields, or just a page in a pdf, which has an image control already extant on it - most likely created with Acrobat DC - and put an image into that control. The source image comes from a Delphi TBitmap. The existing control may already have a (blank?) image in it; if so it would need to be modified/overwritten with the image that I am providing.

Means of obtaining the image data:

I have a bitmap.canvas.handle(hDC).
I have the bitmap available in a stream.
I have an HBITMAP.

I want to place the bitmap into the image control on the PDF.

What is the best method to accomplish this?
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: Bitmap stream to PDF content area

Post by Sasha - Tracker Dev Team »

Hello dkeith,

Well that's because you did not look at the sample that I provided careful enough. You have created the IIXC_Page but did not place it as a content of a page nor created an IPXC_Image from it.

Cheers,
Alex
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
dkeith2
User
Posts: 46
Joined: Mon Aug 14, 2017 8:28 pm

Re: Bitmap stream to PDF content area

Post by dkeith2 »

Well that's because you did not look at the sample that I provided careful enough. You have created the IIXC_Page but did not place it as a content of a page nor created an IPXC_Image from it.
By the time I sent you yesterday's example, I had already tried that. It didn't work. So I tried several other things. That didn't work. As of yesterday, I tried this:

Code: Select all

var
  iPage: IPXC_Page;
  icPage: IIXC_Page;
  i: Integer;
  iInst: IIXC_Inst;
  iContent: IPXC_Content;
  iItems: IPXC_ContentItems;
  iItem: IPXC_ContentItem;
  iCCreator: IPXC_ContentCreator;
  iImage: IPXC_Image;
  iType: TOleEnum;
  cnt,uHB: Cardinal;
  beditable: WordBool;
  bmp: Vcl.Graphics.TBitmap;
  sigPad: TfrmSignaturePad;
  iCoreDoc: IPXC_Document;
begin
  sigPad := TfrmSignaturePad.Create(Nil);
  try
    if sigPad.ShowModal = mrOk then
    begin
      bmp := Vcl.Graphics.TBitmap.Create;
      bmp.LoadFromStream(sigPad.ImageStream);
      uHB := bmp.Handle;
    end;
    if (FPDFEdit.Doc.CoreDoc.Pages.Get_Item(0,iPage) = S_OK) and (iPage.GetContent(CAccessMode_WeakClone,iContent) = S_OK) then
      if (iContent.Get_Items(iItems) = S_OK) and (iItems.Get_Count(cnt) = S_OK) then
        for i := 0 to Pred(cnt) do
          if (iItems.GetItemForEditing(i,iItem) = S_OK) and (iItem.Get_type_(iType) = S_OK) then
            if (iType = CIT_Image) or (iType = CIT_InlineImage) then
            begin
              iInst := IIXC_Inst(FPDFEdit.Inst.GetExtension('IXC'));
              if (iInst.Page_CreateFromHBITMAP(bmp.Handle,0,icPage) = S_OK) and Assigned(icPage) then
              begin
                iCoreDoc := FPDFEdit.Doc.CoreDoc;
                if Assigned(iCoreDoc) and (iPage.Get_Document(iCoreDoc) = S_OK) then
                begin
                  iImage := iCoreDoc.AddImageFromIXCPage(icPage,1);
                  if Assigned(iImage) then
                  begin
                    iCCreator := iCoreDoc.CreateContentCreator;
                    iCCreator.PlaceImage(iImage);
                    if (iCCreator.Detach(iContent) = S_OK) and (iPage.PlaceContent(iContent,PlaceContent_Replace) = S_OK) then
                      ;
                  end;
                end;
              end;
            end;
  finally
    sigPad.Free;
    bmp.Free;
  end;
end;
  
Which doesn't work.

What else is there to do? I've tried swapping handles and many other things that would work if I were using the winapi. Perhaps you could provide a slightly more detailed example?
User avatar
Tracker Supp-Stefan
Site Admin
Posts: 17892
Joined: Mon Jan 12, 2009 8:07 am
Location: London
Contact:

Re: Bitmap stream to PDF content area

Post by Tracker Supp-Stefan »

Hello dkeith2,

Sorry to hear this doesn't work.
I've asked a colleague from the dev team to take a look here, and he said he will post his feedback as soon as possible, but likely tomorrow.

Happy holidays!
Stefan
dkeith2
User
Posts: 46
Joined: Mon Aug 14, 2017 8:28 pm

Re: Bitmap stream to PDF content area

Post by dkeith2 »

Ok, this (partially) works:

Code: Select all

function PDFPlaceSignature: Boolean;
var
  iPage: IPXC_Page;
  icPage: IIXC_Page;
  i: Integer;
  iInst: IIXC_Inst;
  iContent: IPXC_Content;
  iItems: IPXC_ContentItems;
  iItem: IPXC_ContentItem;
  iHandle: Cardinal;
  iImage: IPXC_Image;
  iType: TOleEnum;
  cnt: Cardinal;
  bmp: Vcl.Graphics.TBitmap;
  sigPad: TfrmSignaturePad;
  iCoreDoc: IPXC_Document;
begin
  sigPad := TfrmSignaturePad.Create(Nil);
  try
    Result := False;
    if sigPad.ShowModal = mrOk then
    begin
      bmp := Vcl.Graphics.TBitmap.Create;
      bmp.LoadFromStream(sigPad.ImageStream);
    end;
    if (Doc.CoreDoc.Pages.Get_Item(0,iPage) = S_OK) and (iPage.GetContent(CAccessMode_WeakClone,iContent) = S_OK) then
      if (iContent.Get_Items(iItems) = S_OK) and (iItems.Get_Count(cnt) = S_OK) then
        for i := 0 to Pred(cnt) do
          if (iItems.GetItemForEditing(i,iItem) = S_OK) and (iItem.Get_type_(iType) = S_OK) then
            if (iType = CIT_Image) or (iType = CIT_InlineImage) then
            begin
              iInst := IIXC_Inst(Inst.GetExtension('IXC'));
              if (iInst.Page_CreateFromHBITMAP(bmp.Handle,0,icPage) = S_OK) and Assigned(icPage) then
              begin
                if iPage.Get_Document(iCoreDoc) = S_OK then
                  if Assigned(iCoreDoc) then
                  begin
                    iImage := iCoreDoc.AddImageFromIXCPage(icPage,0);
                    if Assigned(iImage) then
                    begin
                      iImage.Get_Handle(iHandle);
                      iItem.Set_Image_Handle(iHandle);
                      if (iPage.PlaceContent(iContent,PlaceContent_Replace) = S_OK) then
                      begin
                        Result := True;
                        iImage := Nil;
                        icPage := Nil;
                      end;
                    end;
                  end;
              end;
            end;
  finally
    sigPad.Free;
    bmp.Free;
  end;
end;
However, nothing shows up on the PDF image control, unless I call this:

Code: Select all

var
  op: IOperation;
  input: ICabNode;
  options: ICabNode;
const
  ayFlatten: array[Boolean] of UnicodeString = ('LeftAsIs','Flatten');
begin
  op := Inst.CreateOp(Inst.Str2ID('op.annots.flatten',false));
  input := Op.Params.Root['Input'];
  input.Add(dt_IUnknown).v := Doc.CoreDoc;
  options := Op.Params.Root['Options'];
  options['NonPrintableAction'].v := ayFlatten[FlattenAnnots];
  options['FieldsAction'].v := ayFlatten[FlattenFields];
  op.Do_(0); // -0- is the default flag
  LoadStreamAdapter;
  Doc.Save(FStrmAdapt,0,nil,nil,nil,nil,nil,0);
end;
...which saves the changes to the file. Also, depending where on the bitmap I draw the signature, it may show up on the image control, or it may not. Perhaps the coordinate spaces are not mapping 100%? Should I use a matrix or some other coordinate mapping code to make sure that the entire signature bitmap shows up on the image control in the PDF?

Which leads me to the next question, how do I get the changes to the image control to display, without saving the document?

Thanks.
Last edited by dkeith2 on Fri Dec 22, 2017 6:54 pm, edited 1 time in total.
dkeith2
User
Posts: 46
Joined: Mon Aug 14, 2017 8:28 pm

Re: Bitmap stream to PDF content area

Post by dkeith2 »

Which leads me to the next question, how do I get the changes to the image control to display, without saving the document?
If I call RefreshPages from the control, the signature image displays on the image control on the PDF. Is there a way to accomplish this without calling RefreshPages? Something that will only refresh the image control and nothing else on the PDF?
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: Bitmap stream to PDF content area

Post by Sasha - Tracker Dev Team »

Hello dkeith2,

Well as you can clearly see in that sample it works with the Core Document. It creates it (though it can be opened), modifies it and then saves it. Then the document can be opened with the IPXV_Control to obtain the IPXV_Document.
If you do that in the Control directly - you will have to send the appropriate events to refresh the UI (IPXV_Document).
Alternatively, you can use this operation (which will be better in your case):
https://sdkhelp.pdf-xchange.com/vi ... t_addImage
The Operations do all of the Update/Undo-Redo data stuff for you. Using operations in the IPXV level is a way of optimal usage of the SDK.
That operation uses IString, IAFS_Name , IAFS_File , IStream, IIXC_Image as an Src data in Options, so basically you can create the IIXC_Image from the IIXC_Page that you have (try finding this on forums - there are multiple samples on this one) and pass it to the operation with needed parameters.

Cheers,
Alex
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
Post Reply