Search code examples
leadtools-sdk

Append Multiple Images to a PDF Page with LEADTOOLS


Is there some way to add multiple (2, 3 or 4) images to the same page of a PDF file using the LEADTOOLS C API?

The L_SaveBitmap() function takes a SAVEFILEOPTION parameter, where the PageNumber can be set, but setting this to a value greater than 1 causes a new page to be appended. Instead, a value of 1 or 0 causes the file to be overwritten.

The L_SaveFile() function performs similarly; setting the SAVEFILE_MULTIPAGE flag causes a new page to be always appended.

The L_PdfComp..() functions don't seem to be capable of handling pages at all.

Do the MRC functions support handling of pages, i.e. specify which page each image will be stored in? Also, is the file generated of standard PDF format, or it is LEAD-specific?

Any help would be highly appreciated.


Solution

  • To address the part about “is the file generated of standard PDF format, or it is LEAD-specific”, any PDF file saved by any and all LEADTOOLS functions is a standard PDF file, and it should be possible to open it using any standard PDF viewer.
    However, if you wish to append or replace pages using L_SaveBitmap(), the existing PDF file must be a raster-based PDF similar to the output of L_SaveBitmap() itself.

    To work with more general types of PDF, other LEADTOOLS functions can be used, such as the .NET PDFFile class and PDFDocument class.

    The C/C++ code below performs overwriting (creating a new file), appending and replacing a specific page. It also shows how to place 2 images inside a single PDF page.
    The code segments can be combined into one function to test them with any 4 input image files.

    First, create a file with one page, overwriting it if it exists:

    // Create file with first page
    BITMAPHANDLE page1 = { 0 };
    L_LoadBitmap(page1_file, &page1, sizeof BITMAPHANDLE, 24, ORDER_BGR, NULL, NULL);
    page1.XResolution = page1.YResolution = BITMAPHEIGHT(&page1) / 11; //set the DPI to cause 11 inch height.
    L_SaveBitmap(outputPdf_file, &page1, FILE_RAS_PDF_LZW, 24, 0, NULL);
    L_FreeBitmap(&page1);
    

    Next, load an image and append it as a second page to the same PDF file:

    // Append second page
    BITMAPHANDLE page2 = { 0 };
    L_LoadBitmap(page2_file, &page2, sizeof BITMAPHANDLE, 24, ORDER_BGR, NULL, NULL);
    SAVEFILEOPTION SaveOptions = { 0 };
    L_GetDefaultSaveFileOption(&SaveOptions, sizeof SAVEFILEOPTION);
    SaveOptions.PageNumber = 2;
    page2.XResolution = page2.YResolution = BITMAPHEIGHT(&page2) / 11; //set the DPI to cause 11 inch height.
    L_SaveBitmap(outputPdf_file, &page2, FILE_RAS_PDF_LZW, 24, 0, &SaveOptions);
    L_FreeBitmap(&page2);
    

    Finally, load 2 images, combine them into one image and replace the first page with the image combined from the newly-loaded 2 images:

    BITMAPHANDLE page2_1 = { 0 }, page2_2 = { 0 };
    // Load 2 iamges for one page
    L_LoadBitmap(page2_1_file, &page2_1, sizeof BITMAPHANDLE, 24, ORDER_BGR, NULL, NULL);
    L_LoadBitmap(page2_2_file, &page2_2, sizeof BITMAPHANDLE, 24, ORDER_BGR, NULL, NULL);
    
    L_UINT w = max(BITMAPWIDTH(&page2_1), BITMAPWIDTH(&page2_2));
    L_UINT h = BITMAPHEIGHT(&page2_1) + BITMAPHEIGHT(&page2_2);
    BITMAPHANDLE combinedPage = { 0 };
    // Create empty bitmap
    L_CreateBitmap(&combinedPage, sizeof BITMAPHANDLE, TYPE_CONV, w, h, 24, ORDER_BGR, NULL, BOTTOM_LEFT, NULL, 0);
    // Copy the first image into the empty bitmap
    L_CombineBitmap(&combinedPage, 0, 0, BITMAPWIDTH(&page2_1), BITMAPHEIGHT(&page2_1), &page2_1, 0, 0, CB_DST_0 | CB_OP_ADD | CB_RAWCOMBINE, 0);
    L_FreeBitmap(&page2_1);
    // Copy the second image below the first image
    L_CombineBitmap(&combinedPage, 0, BITMAPHEIGHT(&page2_1), BITMAPWIDTH(&page2_2), BITMAPHEIGHT(&page2_2), &page2_2, 0, 0, CB_DST_0 | CB_OP_ADD | CB_RAWCOMBINE, 0);
    L_FreeBitmap(&page2_2);
    SaveOptions.PageNumber = 1;
    SaveOptions.Flags |= ESO_REPLACEPAGE; // add the replace flag to put the combined image instead of the old page1
    combinedPage.XResolution = combinedPage.YResolution = BITMAPHEIGHT(&combinedPage) / 11; //set the DPI to cause 11 inch height.
    L_SaveBitmap(outputPdf_file, &combinedPage, FILE_RAS_PDF_LZW, 24, 0, &SaveOptions);
    L_FreeBitmap(&combinedPage);
    

    The following part was added after the answer got accepted, to address a comment:

    It is possible to insert multiple images into a single PDF page without combining them first, but not using the L_SaveBitmap() function. Instead, the Document Writer functions need to be used as shown in the following code sample.

    The code below loads 2 images and puts them into an EMF memory file. It then draws an ellipse on top of them to show that any Windows GDI graphics object can be added (for example, you can add text using TextOut() or other GDI functions). After that, the EMF page is saved as PDF using LEADTOOLS Document Writer.

    BITMAPHANDLE image1 = { 0 }, image2 = { 0 };
    // Load 2 iamges for one page
    L_LoadBitmap(image1_file, &image1, sizeof BITMAPHANDLE, 24, ORDER_BGR, NULL, NULL);
    L_LoadBitmap(image2_file, &image2, sizeof BITMAPHANDLE, 24, ORDER_BGR, NULL, NULL);
    L_UINT w = max(BITMAPWIDTH(&image1), BITMAPWIDTH(&image2));
    L_UINT h = BITMAPHEIGHT(&image1) + BITMAPHEIGHT(&image2);
    
    // Create a memory metafile and paint both bitmaps in it
    HDC hdcEmf = CreateEnhMetaFile(NULL, NULL, NULL, NULL);
    Rectangle(hdcEmf, 0, 0, w, h);
    
    RECT rc1 = { 0, 0, BITMAPWIDTH(&image1), BITMAPHEIGHT(&image1) };
    L_PaintDC(hdcEmf, &image1, NULL, NULL, &rc1, NULL, SRCCOPY);
    L_FreeBitmap(&image1);
    
    RECT rc2 = { 0, BITMAPHEIGHT(&image1), BITMAPWIDTH(&image2), BITMAPHEIGHT(&image1) + BITMAPHEIGHT(&image2) };
    L_PaintDC(hdcEmf, &image2, NULL, NULL, &rc2, NULL, SRCCOPY);
    L_FreeBitmap(&image2);
    
    Ellipse(hdcEmf, w / 4, h / 4, w * 3 / 4, h * 3 / 4);
    
    HENHMETAFILE hemf = CloseEnhMetaFile(hdcEmf);
    
    DOCWRTPDFOPTIONS pdf = { 0 };
    L_DOUBLE dTextScale = 0.5;
    DOCUMENTWRITER_HANDLE hDocument = 0;
    DOCWRTEMFPAGE Page = { 0 };
    pdf.PdfProfile = DOCWRTPDFPROFILE_PDF;
    pdf.Options.uStructSize = sizeof(pdf);
    pdf.Options.nDocumentResolution = 300;
    // Setup empty page size based on images size
    pdf.Options.dEmptyPageWidth = w / 300.0;
    pdf.Options.dEmptyPageHeight = h / 300.0;
    pdf.Options.nEmptyPageResolution = 300;
    
    L_DocWriterInit(&hDocument, outputPdf_file, DOCUMENTFORMAT_PDF, &pdf, NULL, NULL);
    Page.hEmf = hemf;
    Page.pdwTextScale = &dTextScale;
    L_DocWriterAddPage(hDocument, DOCWRTPAGETYPE_EMF, (L_VOID*)&Page);
    L_DocWriterFinish(hDocument);
    
    DeleteEnhMetaFile(hemf);