Examples / text_formatting / activex_cpp

Text Formatting

A complete, runnable activex_cpp program — 119 lines, shipped in your download.

Demonstrates Text

Same example, other languages: c cpp cpp_linux csharp delphi php python vbnet

examples/activex_cpp/text_formatting/text_formatting.cpp 119 lines
// ============================================================================
//  text_formatting -- C++ ActiveX (COM) port, following
//  examples/activex/text_formatting/text_formatting.vbs
//
//  Lays sample.txt out into three justified COLUMNS.
//
//  The layout is driven entirely by the page-break callback: WriteFText fills
//  the current text rectangle, and when it runs out the engine asks what to do
//  next. The handler either moves the rectangle to the next column (same page)
//  or closes the page and starts a new one. That is the whole multi-column
//  algorithm -- there is no second pass.
//
//  CreateNewPDF RESETS the page-break proc in the engine, so SetOnPageBreakProc
//  has to be (re)armed AFTER it, not before.
// ============================================================================
#import "..\\..\\wrappers\\activex\\LumasPdfAX.tlb" no_namespace named_guids

#include <windows.h>

#include "axcommon.h"

#include <cstdio>
#include <string>

// Output-rectangle state shared with the page-break event.
static ILumasPDFPtr pdf;
static double gPosX, gPosY, gWidth, gHeight, gDistance;
static int gColumn, gColCount;

class BreakSink : public AxSink {
public:
    long OnError(long, const wchar_t*, long) override { return 0; }

    // Places the next column or starts a new page.
    long OnPageBreak(double, double, bool pageBreak) override {
        pdf->SetPageCoords(pcTopDown);          // we use top down coordinates
        ++gColumn;
        // pageBreak is true if the string contains an explicit page-break tag.
        if (!pageBreak && gColumn < gColCount) {
            // change the output rectangle to the next column, do NOT close the page
            double x = gPosX + gColumn * (gWidth + gDistance);
            pdf->SetTextRect(x, gPosY, gWidth, gHeight);
        } else {
            // the page is full: close it and append a new one
            pdf->EndPage();
            pdf->Append();
            pdf->SetTextRect(gPosX, gPosY, gWidth, gHeight);
            gColumn = 0;
        }
        return 0;                               // we do not change the alignment
    }
};

static std::string ReadAll(const std::string& path) {
    std::string out;
    FILE* f = fopen(path.c_str(), "rb");
    if (!f) return out;
    char buf[8192];
    size_t n;
    while ((n = fread(buf, 1, sizeof(buf), f)) > 0) out.append(buf, n);
    fclose(f);
    return out;
}

int main() {
    ChdirToExe();
    ComInit com;
    if (!com.ok()) return 1;

    // Stage sample.txt next to the exe (from the shared test_files folder).
    std::string sample = OutFile("sample.txt");
    if (ReadAll(sample).empty())
        CopyFileA("E:\\LUMASPDFSDK\\examples\\test_files\\sample.txt", sample.c_str(), FALSE);
    std::string fText = ReadAll(sample);

    if (FAILED(pdf.CreateInstance(L"LumasPdf.PDF"))) return 1;
    BreakSink sink;
    sink.Advise(pdf);
    pdf->RaiseExceptions = VARIANT_FALSE;

    pdf->SetDocInfoW(diCreator, B("LumasPdf ActiveX test app"));
    pdf->SetDocInfoW(diSubject, B("Multi-column text"));
    pdf->SetDocInfoW(diTitle, B("Multi-column text"));
    pdf->SetPageCoords(pcTopDown);
    if (!pdf->CreateNewPDFW(B(""))) { std::printf("CreateNewPDF failed\n"); return 1; }
    // CreateNewPDF resets the page-break proc in the engine, so (re)arm it now.
    pdf->SetOnPageBreakProc();

    // Initialize the output rectangle, number of columns and so on.
    gColCount = 3;                 // the VB6 form combo default was 3 columns
    gColumn = 0;
    gDistance = 10;
    gPosX = 50;
    gPosY = 50;

    pdf->Append();                 // append a new page
    gHeight = pdf->GetPageHeight() - 100;
    gWidth = (pdf->GetPageWidth() - 100 - (gColCount - 1) * gDistance) / gColCount;

    pdf->SetTextRect(gPosX, gPosY, gWidth, gHeight);
    pdf->SetFontW(B("Arial"), fsNone, 9, VARIANT_TRUE, cp1252);  // a font is always required
    pdf->WriteFTextW(taJustify, B(fText));                       // fires OnPageBreak
    pdf->EndPage();                // close the last page

    int rc = 0;
    if (pdf->HaveOpenDoc()) {
        std::string outFile = OutFile();
        if (!pdf->OpenOutputFileW(B(outFile))) {
            std::printf("OpenOutputFile failed\n");
            rc = 1;
        } else if (pdf->CloseFile()) {
            std::printf("OK: %s\n", outFile.c_str());
        }
    }
    sink.Unadvise();
    pdf = nullptr;
    return rc;
}

This file is in the SDK at examples/activex_cpp/text_formatting/text_formatting.cpp. The build fails if this page and that file ever differ.