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 )