dataops (dataops.cpp) – this example shows how to create documents both direct file (write-only) and a memory-based documents. It mostly uses API for memory-based PDF documents. It contains several sections, which create a PDF document with a rounded filled rectangle on a page. Such document is saved into a file (directly, or through a memory buffer), same as the file loaded and re-saved. It also compares whether the result file content is the same for both save to a disk and save to a memory buffer.

    1 /*
    2  * (c) 2013-2016 http://www.litePDF.cz
    3  * (c) 2017 zyx [@:] zyx gmx [dot] us
    4  *
    5  * This software is provided 'as-is', without any express or implied
    6  * warranty.  In no event will the authors be held liable for any damages
    7  * arising from the use of this software.
    8  *
    9  * Permission is granted to anyone to use this software for any purpose,
   10  * including commercial applications, and to alter it and redistribute it
   11  * freely, subject to the following restrictions:
   12  *
   13  * 1. The origin of this software must not be misrepresented; you must not
   14  *    claim that you wrote the original software. If you use this software
   15  *    in a product, an acknowledgment in the product documentation would be
   16  *    appreciated but is not required.
   17  * 2. Altered source versions must be plainly marked as such, and must not be
   18  *    misrepresented as being the original software.
   19  * 3. This notice may not be removed or altered from any source distribution.
   20  */ 
   21 
   22 #include <windows.h>
   23 #include <stdio.h>
   24 #include <string.h>
   25 #include <string>
   26 
   27 #include "share/litePDF.h"
   28 
   29 static std::string to_string(unsigned int num)
   30 {
   31    char buff[128];
   32 
   33    sprintf(buff, "%u", num);
   34 
   35    return std::string(buff);
   36 }
   37 
   38 static void drawPage(litePDF::TLitePDF &litePDF)
   39 {
   40    // add a new page to it, with large-enough pixel scale
   41    HDC hDC = litePDF.AddPage(litePDF.MMToUnit(210), litePDF.MMToUnit(297), 2100, 2970, LitePDFDrawFlag_None);
   42 
   43    HGDIOBJ oldBrush, oldPen;
   44 
   45    oldBrush = SelectObject(hDC, GetStockObject(LTGRAY_BRUSH));
   46    oldPen = SelectObject(hDC, GetStockObject(BLACK_PEN));
   47 
   48    // draw rectangle
   49    RoundRect(hDC, 200, 200, 1900, 2770, 300, 300);
   50 
   51    SelectObject(hDC, oldPen);
   52    SelectObject(hDC, oldBrush);
   53 
   54    // finish drawing
   55    litePDF.FinishPage(hDC);
   56 }
   57 
   58 static void saveToData(litePDF::TLitePDF &litePDF,
   59                        BYTE **pdata,
   60                        unsigned int &dataLength)
   61 {
   62    dataLength = 0;
   63    *pdata = NULL;
   64 
   65    if (!litePDF.SaveToData(NULL, &dataLength)) {
   66       throw TLitePDFException(ERROR_CANNOT_MAKE, "Failed to get data length");
   67    }
   68 
   69    if (!dataLength) {
   70       throw TLitePDFException(ERROR_CANNOT_MAKE, "Returned data length is 0");
   71    }
   72 
   73    *pdata = (BYTE *) malloc(sizeof(BYTE) * dataLength);
   74    if (!*pdata) {
   75       std::string msg = "Failed to allocate " + to_string(dataLength) + " bytes";
   76       throw TLitePDFException(ERROR_OUTOFMEMORY, msg.c_str());
   77    }
   78 
   79    if (!litePDF.SaveToData(*pdata, &dataLength)) {
   80       throw TLitePDFException(ERROR_CANNOT_MAKE, "Failed to get data");
   81    }
   82 }
   83 
   84 static void saveDataToFile(const char *fileName,
   85                            const BYTE *data,
   86                            unsigned int dataLength)
   87 {
   88    FILE *f = fopen(fileName, "wb");
   89    if (!f) {
   90       std::string msg = "Failed to open " + std::string(fileName);
   91       throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
   92    }
   93 
   94    if (fwrite(data, sizeof(BYTE), dataLength, f) != dataLength) {
   95       fclose(f);
   96       std::string msg = "Failed to write to " + std::string(fileName);
   97       throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
   98    }
   99 
  100    fclose(f);
  101 }
  102 
  103 static void cmpFileAndData(const char *fileName,
  104                            const BYTE *data,
  105                            unsigned int dataLength)
  106 {
  107    FILE *f = fopen(fileName, "rb");
  108    if (!f) {
  109       std::string msg = "Failed to open " + std::string(fileName);
  110       throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
  111    }
  112 
  113    if (fseek(f, 0, SEEK_END) != 0) {
  114       fclose(f);
  115       throw TLitePDFException(ERROR_CANNOT_MAKE,
  116                               "Failed to move to the end of the file");
  117    }
  118 
  119    long fileLength = ftell(f);
  120    if (fileLength != (long) dataLength) {
  121       fclose(f);
  122       std::string msg = "File length (" + to_string(fileLength) +
  123                         ") differs from data length (" +
  124                         to_string(dataLength) + ")";
  125       throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
  126    }
  127 
  128    if (fseek(f, 0, SEEK_SET) != 0) {
  129       fclose(f);
  130       throw TLitePDFException(ERROR_CANNOT_MAKE,
  131                               "Failed to move to the beginning of the file");
  132    }
  133 
  134    BYTE buff[1024];
  135    unsigned int read, dataOffset = 0;
  136    while(read = fread(buff, sizeof(BYTE), 1024, f), read > 0) {
  137       if (memcmp(buff, data + dataOffset, read) != 0) {
  138          fclose(f);
  139          throw TLitePDFException(ERROR_CANNOT_MAKE,
  140                                  "File and data content differs");
  141       }
  142 
  143       dataOffset += read;
  144 
  145       if (feof(f)) {
  146          break;
  147       }
  148    }
  149 
  150    fclose(f);
  151 
  152    if (dataOffset != dataLength) {
  153       std::string msg = "Did not finish with dataOffset (" +
  154                         to_string(dataOffset) +
  155                         ") at the end of data (" + to_string(dataLength) + ")";
  156       throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
  157    }
  158 }
  159 
  160 static void cmpDataAndData(const BYTE *data1,
  161                            unsigned int data1Length,
  162                            const BYTE *data2,
  163                            unsigned int data2Length)
  164 {
  165    if (data1Length != data2Length) {
  166       std::string msg = "data1 length (" + to_string(data1Length) +
  167                         ") differs from data2 length (" +
  168                         to_string(data2Length) + ")";
  169       throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
  170    }
  171 
  172    if (0 != memcmp(data1, data2, data1Length)) {
  173       throw TLitePDFException(ERROR_CANNOT_MAKE, "Data contents differ");
  174    }
  175 }
  176 
  177 int main(void)
  178 {
  179    BYTE *data1 = NULL, *data2 = NULL;
  180    unsigned int data1Length, data2Length;
  181    int res = 0;
  182 
  183    using namespace litePDF;
  184 
  185    try {
  186       TLitePDF litePDF;
  187 
  188       //-----------------------------------------------------------------
  189 
  190       // begin write-only PDF file
  191       litePDF.CreateFileDocument("dataops-file1.pdf");
  192 
  193       // fill a page
  194       drawPage(litePDF);
  195 
  196       // close the document
  197       litePDF.Close();
  198 
  199       //-----------------------------------------------------------------
  200 
  201       // begin write-only PDF file
  202       litePDF.CreateMemDocument();
  203 
  204       // fill a page
  205       drawPage(litePDF);
  206 
  207       // save memory-based PDF to file
  208       litePDF.SaveToFile("dataops-file2.pdf");
  209 
  210       // close the document
  211       litePDF.Close();
  212 
  213       //-----------------------------------------------------------------
  214 
  215       // create memory PDF
  216       litePDF.CreateMemDocument();
  217 
  218       // fill a page
  219       drawPage(litePDF);
  220 
  221       // save to data; the 'data1' and 'data1Length' stores saved PDF now
  222       saveToData(litePDF, &data1, data1Length);
  223 
  224       // close the document
  225       litePDF.Close();
  226 
  227       //-----------------------------------------------------------------
  228 
  229       // save data to file
  230       saveDataToFile("dataops-data1.pdf", data1, data1Length);
  231 
  232       // compare file and data - the content should be the same.
  233       // cannot compare write-only file PDF with memory-based, because the way
  234       // they are written into the disk are different
  235       cmpFileAndData("dataops-file2.pdf", data1, data1Length);
  236 
  237       //-----------------------------------------------------------------
  238 
  239       // load from file
  240       litePDF.LoadFromFile("dataops-file2.pdf", NULL, false);
  241 
  242       // save to data
  243       saveToData(litePDF, &data2, data2Length);
  244 
  245       // close the document
  246       litePDF.Close();
  247 
  248       //-----------------------------------------------------------------
  249 
  250       // save data to file
  251       saveDataToFile("dataops-data2.pdf", data2, data2Length);
  252 
  253       // free the data1 and swap with data2, it's reused
  254       free(data1);
  255       data1 = data2;
  256       data2 = NULL;
  257       data1Length = data2Length;
  258 
  259       //-----------------------------------------------------------------
  260 
  261       // load from file
  262       litePDF.LoadFromFile("dataops-file2.pdf", NULL, true);
  263 
  264       // save to data
  265       saveToData(litePDF, &data2, data2Length);
  266 
  267       // close the document
  268       litePDF.Close();
  269 
  270       // save data to file
  271       saveDataToFile("dataops-data3.pdf", data2, data2Length);
  272 
  273       //-----------------------------------------------------------------
  274 
  275       // compare data - the content should be the same
  276       cmpDataAndData(data1, data1Length, data2, data2Length);
  277 
  278       // free the data2, it's reused
  279       free(data2);
  280       data2 = NULL;
  281 
  282       //-----------------------------------------------------------------
  283 
  284       // load from data
  285       litePDF.LoadFromData(data1, data1Length, NULL);
  286 
  287       // save to data
  288       saveToData(litePDF, &data2, data2Length);
  289 
  290       // close the document
  291       litePDF.Close();
  292 
  293       // save data to file
  294       saveDataToFile("dataops-data4.pdf", data2, data2Length);
  295 
  296       //-----------------------------------------------------------------
  297 
  298       // compare data - the content should be the same
  299       cmpDataAndData(data1, data1Length, data2, data2Length);
  300 
  301       // free the data2, it's reused
  302       free(data2);
  303       data2 = NULL;
  304 
  305       //-----------------------------------------------------------------
  306 
  307    } catch (TLitePDFException &ex) {
  308       fprintf(stderr, "litePDF Exception: %x: %s\n", ex.getCode(), ex.getMessage());
  309       res = 1;
  310    }
  311 
  312    if (data1) {
  313       free(data1);
  314    }
  315 
  316    if (data2) {
  317       free(data2);
  318    }
  319 
  320    return res;
  321 }