PDF-Make

 view release on metacpan or  search on metacpan

src/pdfmake_watermark.c  view on Meta::CPAN

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <time.h>

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

/* Helper for appending strings to buffer */
static void pdfmake_buf_append_str(pdfmake_buf_t *buf, const char *s)
{
    pdfmake_buf_append_cstr(buf, s);
}

/*----------------------------------------------------------------------------
 * Approximate character widths for Standard 14 fonts (simplified)
 * Real implementation would use AFM data
 *--------------------------------------------------------------------------*/

/* Average character width as fraction of font size for common fonts */
static double get_char_width_factor(const char *font_name)
{
    if (!font_name) return 0.5;
    
    /* Courier is fixed-width */
    if (strstr(font_name, "Courier")) {
        return 0.6;  /* Fixed width */
    }
    
    /* Helvetica/Arial style */
    if (strstr(font_name, "Helvetica") || strstr(font_name, "Arial")) {
        return 0.52;
    }
    
    /* Times/serif style */
    if (strstr(font_name, "Times")) {
        return 0.45;
    }
    
    /* Default */
    return 0.5;
}

/*----------------------------------------------------------------------------
 * Default options initialization
 *--------------------------------------------------------------------------*/

void pdfmake_watermark_opts_init(pdfmake_watermark_opts_t *opts)
{
    if (!opts) return;
    
    memset(opts, 0, sizeof(*opts));
    opts->position = PDFMAKE_WM_POS_CENTER;
    opts->rotation = 0.0;
    opts->opacity = 0.3;
    opts->scale = 1.0;
    opts->x_offset = 0.0;
    opts->y_offset = 0.0;
    opts->as_overlay = 0;  /* Behind content by default */
    
    opts->font_name = "Helvetica-Bold";
    opts->font_size = 72.0;
    opts->color[0] = 0.7;  /* Light gray */
    opts->color[1] = 0.7;
    opts->color[2] = 0.7;
    
    opts->tile_spacing_x = 150.0;
    opts->tile_spacing_y = 150.0;
}

void pdfmake_stamp_opts_init(pdfmake_stamp_opts_t *opts)
{
    if (!opts) return;
    
    memset(opts, 0, sizeof(*opts));
    opts->position = PDFMAKE_WM_POS_BOTTOM_CENTER;
    opts->margin_x = 36.0;  /* Half inch */
    opts->margin_y = 36.0;
    opts->font_name = "Helvetica";
    opts->font_size = 10.0;
    opts->color[0] = 0.0;  /* Black */
    opts->color[1] = 0.0;
    opts->color[2] = 0.0;
}

/*----------------------------------------------------------------------------
 * Text metrics
 *--------------------------------------------------------------------------*/

double pdfmake_text_width_approx(const char *text, const char *font_name,
                                  double font_size)
{
    double factor;
    size_t len;

    if (!text) return 0.0;
    
    factor = get_char_width_factor(font_name);
    len = strlen(text);
    
    return len * font_size * factor;
}

/*----------------------------------------------------------------------------
 * Watermark creation
 *--------------------------------------------------------------------------*/

pdfmake_watermark_t *pdfmake_watermark_text(pdfmake_doc_t *doc,
                                             const char *text,
                                             const pdfmake_watermark_opts_t *opts)
{
    pdfmake_watermark_t *wm;

    (void)doc;
    if (!text) return NULL;
    
    wm = calloc(1, sizeof(pdfmake_watermark_t));
    if (!wm) return NULL;
    

src/pdfmake_watermark.c  view on Meta::CPAN

 *--------------------------------------------------------------------------*/

pdfmake_err_t pdfmake_page_add_watermark(pdfmake_page_t *page,
                                          pdfmake_watermark_t *wm)
{
    pdfmake_doc_t *doc;
    char gs_name[32];
    char font_res_name[32];
    char img_name[32];
    const char *base_font;
    pdfmake_buf_t buf;
    const uint8_t *wm_data;
    size_t wm_len;
    const uint8_t *old_data = NULL;
    size_t old_len = 0;
    pdfmake_obj_t *old_obj;
    pdfmake_buf_t merged;

    if (!page || !wm) return PDFMAKE_EINVAL;

    /* Fully transparent watermark: no-op. */
    if (wm->opts.opacity <= 0.0) {
        return PDFMAKE_OK;
    }
    
    doc = page->doc;
    
    gs_name[0] = '\0';
    if (wm->opts.opacity < 1.0) {
        if (wm->extgstate_num == 0) {
            wm->extgstate_num = pdfmake_doc_get_opacity_extgstate(doc, wm->opts.opacity);
        }
        if (wm->extgstate_num) {
            snprintf(gs_name, sizeof(gs_name), "GS%u", wm->extgstate_num);
            pdfmake_page_add_extgstate(page, gs_name, wm->extgstate_num);
        }
    }
    
    /* Font name for text watermarks */
    strcpy(font_res_name, "F1");
    if (wm->type == PDFMAKE_WM_TYPE_TEXT) {
        /* Add font to page resources if not present */
        base_font = wm->opts.font_name ? wm->opts.font_name : "Helvetica";
        pdfmake_page_add_font(page, font_res_name, base_font);
    }
    
    /* Image name for image watermarks */
    strcpy(img_name, "WmImg0");
    if (wm->type == PDFMAKE_WM_TYPE_IMAGE) {
        snprintf(img_name, sizeof(img_name), "WmImg%u", wm->data.image.image_obj);
        pdfmake_page_add_image(page, img_name, wm->data.image.image_obj);
    }
    
    /* Generate watermark content */
    pdfmake_buf_init(&buf);
    
    generate_watermark_content(wm, page, &buf, 
                               gs_name[0] ? gs_name : NULL,
                               font_res_name, img_name);
    
    /* Merge watermark with existing page content (overlay/underlay). */
    wm_data = pdfmake_buf_data(&buf);
    wm_len = pdfmake_buf_len(&buf);

    if (page->has_content && page->contents_num) {
        old_obj = pdfmake_doc_get(doc, page->contents_num);
        if (old_obj && old_obj->kind == PDFMAKE_STREAM && old_obj->as.stream) {
            old_data = old_obj->as.stream->raw;
            old_len = old_obj->as.stream->raw_len;
        }
    }

    if (!old_data || old_len == 0) {
        pdfmake_page_set_content(page, wm_data, wm_len);
    } else {
        pdfmake_buf_init(&merged);

        if (wm->opts.as_overlay) {
            pdfmake_buf_append(&merged, old_data, old_len);
            pdfmake_buf_append_byte(&merged, '\n');
            pdfmake_buf_append(&merged, wm_data, wm_len);
        } else {
            pdfmake_buf_append(&merged, wm_data, wm_len);
            pdfmake_buf_append_byte(&merged, '\n');
            pdfmake_buf_append(&merged, old_data, old_len);
        }

        pdfmake_page_set_content(page, pdfmake_buf_data(&merged), pdfmake_buf_len(&merged));
        pdfmake_buf_free(&merged);
    }
    
    pdfmake_buf_free(&buf);
    
    return PDFMAKE_OK;
}

pdfmake_err_t pdfmake_doc_add_watermark(pdfmake_doc_t *doc,
                                         pdfmake_watermark_t *wm)
{
    size_t page_count;
    size_t i;
    pdfmake_page_t *page;
    pdfmake_err_t err;

    if (!doc || !wm) return PDFMAKE_EINVAL;
    
    page_count = pdfmake_doc_page_count(doc);
    
    for (i = 0; i < page_count; i++) {
        page = pdfmake_doc_get_page(doc, i);
        if (page) {
            err = pdfmake_page_add_watermark(page, wm);
            if (err != PDFMAKE_OK) return err;
        }
    }
    
    return PDFMAKE_OK;
}

pdfmake_err_t pdfmake_doc_add_watermark_range(pdfmake_doc_t *doc,
                                               pdfmake_watermark_t *wm,
                                               int start_page,
                                               int end_page)
{
    size_t page_count;
    int i;
    pdfmake_page_t *page;
    pdfmake_err_t err;

    if (!doc || !wm) return PDFMAKE_EINVAL;
    
    page_count = pdfmake_doc_page_count(doc);
    
    if (start_page < 0) start_page = 0;
    if (end_page < 0 || (size_t)end_page >= page_count) {
        end_page = (int)page_count - 1;
    }
    



( run in 0.451 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )