/*********************************************************************
ADOBE SYSTEMS INCORPORATED
Copyright (C) 2000-2003 Adobe Systems Incorporated
All rights reserved.
NOTICE: Adobe permits you to use, modify, and distribute this file
in accordance with the terms of the Adobe license agreement
accompanying it. If you have received this file from a source other
than Adobe, then your use, modification, or distribution of it
requires the prior written permission of Adobe.
---------------------------------------------------------------------
Watermark.cpp
- Uses the PDFEdit API to add a watermark that is a transparent text
in the center of the page.
- Performing this operation involves:
1. Acquiring the page that may be current page or every page.
2. Creating a PDEFont reference.
3. Initializing the graphics state, color space, and text matrix
to be associated with the text.
4. Creating the PDEText element and adding it to the contents of
the page.
*********************************************************************/
// PDFL include
#ifdef MAC_ENV
#include "macUtils.h"
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include "PDFInit.h"
#include "
CosCalls.h"
#include "
CorCalls.h"
#include "
ASCalls.h"
#include "
PDCalls.h"
#include "
PERCalls.h"
#include "
PEWCalls.h"
#include "
PIExcept.h"
#include "PagePDECntCalls.h"
#include "MyPDFLibUtils.h"
// system files
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
// header files in this project
#include "Watermark.h"
#ifndef MAC_PLATFORM
const double pi = 3.1415926535;
#endif
// functins in this file
static void CalculateTextPosition( const char * text,
PDEFont font,
int tSize, double theta,
PDEGraphicState gState,
int * px, int * py);
/* Serialize is called with the PDF Library already initialized. */
bool Serialize( const char *inputFileName, const char *outputFileName, const char *watermark )
{
bool retval;
ASFileSys asFileSys =
ASGetDefaultFileSys();
volatile
ASPathName asPathName =
NULL;
volatile
PDDoc pdDoc =
NULL;
DURING
// Open the source document
#ifdef MAC_PLATFORM
asPathName = GetMacPath(( char *)inputFileName);
#else
asPathName =
ASFileSysCreatePathName( asFileSys,
ASAtomFromString( "Cstring" ), inputFileName, 0 );
#endif
pdDoc =
PDDocOpen(asPathName,
NULL,
NULL, true );
ASFileSysReleasePath(asFileSys, asPathName);
// Actually add the watermark to the PDDoc
if (AddWatermark( pdDoc, watermark )== false )
printf( "Filaed to add watermark\n\n" );
// Save the result with the specified output file name
PDSaveFlags flags =
PDSaveFull |
PDSaveCollectGarbage |
PDSaveLinearized
|
PDSaveBinaryOK |
PDSaveKeepModDate;
#ifdef MAC_PLATFORM
asPathName = GetMacPath(( char *)outputFileName);
#else
asPathName =
ASFileSysCreatePathName( asFileSys,
ASAtomFromString( "Cstring" ), outputFileName, 0 );
#endif
PDDocSave( pdDoc, flags, asPathName, asFileSys,
NULL,
NULL );
ASFileSysReleasePath(asFileSys, asPathName);
// Done with the doc, close it.
PDDocClose( pdDoc );
retval = true ;
HANDLER
if (asPathName !=
NULL)
ASFileSysReleasePath(asFileSys, asPathName);
if (pdDoc !=
NULL)
PDDocClose( pdDoc );
retval = false ;
END_HANDLER
return retval;
}
/* AddWatermark
** ------------------------------------------------------
**
** Function to add a string of text as watermark to a PDF.
*/
bool AddWatermark(
PDDoc pdDoc, const char *text )
{
if (text ==
NULL) return false ;
PDPage pdPage;
ASFixedRect cropBox;
char errorMsg[256];
ASInt32 errorCode = 0;
PDEFont pdeFont =
NULL;
PDEContent volatile pdeContent =
NULL;
PDEText volatile pdeText =
NULL;
DURING
// take the first page as base page
int nPageNum = 0;
if (mPage > 0) nPageNum = mPage -1;
pdPage =
PDDocAcquirePage (pdDoc, nPageNum);
PDPageGetCropBox (pdPage, &cropBox);
PDPageRelease(pdPage);
// Initialize the font descriptor then create the font reference.
// Because we're using one of the base 14 Type 1 fonts, we only
// need to pass a small amount of information to PDEFontCreate().
PDEFontAttrs pdeFontAttrs;
memset(&pdeFontAttrs, 0, sizeof (pdeFontAttrs));
pdeFontAttrs.
name =
ASAtomFromString( "Times-Roman" );
pdeFontAttrs.
type =
ASAtomFromString( "Type1" );
// Create the font reference.
pdeFont =
PDEFontCreate(&pdeFontAttrs, sizeof (pdeFontAttrs), 0, 255, 0,
0,
ASAtomNull, 0, 0, 0, 0);
HANDLER
ASGetErrorString( ASGetExceptionErrorCode(), errorMsg, 256 );
return false ;
END_HANDLER
// color arrangement
PDEColorSpace pdeColorSpace;
// gray:
if (mColor == COLOR_GRAY)
pdeColorSpace =
PDEColorSpaceCreateFromName (
ASAtomFromString( "DeviceGray" ));
// rgb:
else
pdeColorSpace =
PDEColorSpaceCreateFromName (
ASAtomFromString( "DeviceRGB" ));
// extensive graphics state
PDEExtGState pdeExtGState =
NULL;
DURING
// create extensive graphics state
pdeExtGState =
PDEExtGStateCreateNew(
PDDocGetCosDoc(pdDoc));
// set opacity values
PDEExtGStateSetOpacityFill(pdeExtGState,
FloatToASFixed(mOpacity));
PDEExtGStateSetOpacityStroke(pdeExtGState,
FloatToASFixed(mOpacity));
HANDLER
if (pdeExtGState) {
PDERelease((
PDEObject) pdeExtGState);
pdeExtGState =
NULL;
}
END_HANDLER
// The graphics state controls the various style properties of the text
// including color, weight, and so forth.
PDEGraphicState gState;
memset (&gState, 0, sizeof (
PDEGraphicState));
gState.strokeColorSpec.space = gState.fillColorSpec.space = pdeColorSpace;
// Color
if (mColor == COLOR_RED)
gState.strokeColorSpec.value.color[0] = gState.fillColorSpec.value.color[0] =
FloatToASFixed(0.9);
else if (mColor == COLOR_GREEN)
gState.strokeColorSpec.value.color[1] = gState.fillColorSpec.value.color[1] =
FloatToASFixed(0.9);
else if (mColor == COLOR_BLUE)
gState.strokeColorSpec.value.color[2] = gState.fillColorSpec.value.color[2] =
FloatToASFixed(0.9);
// other parameters
gState.miterLimit =
fixedTen;
gState.flatness =
fixedOne;
gState.lineWidth =
fixedOne;
gState.extGState = pdeExtGState;
gState.wasSetFlags = kPDEMiterLimitWasSet | kPDEFlatnessWasSet |
kPDELineWidthWasSet |
kPDEExtGStateWasSet;
// Fill out the text matrix, which determines the point
// size of the text and where it will is drawn on the page.
// First, translation.
// to put the text centered in the page, we need to
// calculatte position of the left-bottom of the text.
int dx, dy;
CalculateTextPosition( text, pdeFont, mFontSize, mAngle*pi/180,
gState, &dx, &dy);
// translation matrix
ASDoubleMatrix textMatrix;
memset (&textMatrix, 0, sizeof (textMatrix));
textMatrix.
a = 1; // x scale
textMatrix.
b = 0; // rotate & skew
textMatrix.
c = 0; // rotate & skew
textMatrix.
d = 1; // y scale
ASDouble xBox = (FixedToDouble(cropBox.
right) - FixedToDouble(cropBox.
left))/2;
textMatrix.
h = FixedToDouble(cropBox.
left) + xBox - dx; // x translation
ASDouble yBox = (FixedToDouble(cropBox.
top) - FixedToDouble(cropBox.
bottom))/2;
textMatrix.
v = FixedToDouble(cropBox.
bottom) + yBox - dy; // y translation
// next, rotate text with angle theta
ASDoubleMatrix rotateMatrix;
memset (&rotateMatrix, 0, sizeof (rotateMatrix));
rotateMatrix.
a = cos(pi*mAngle / 180);
rotateMatrix.
b = sin(pi*mAngle / 180);
rotateMatrix.
c = sin(-pi*mAngle / 180);
rotateMatrix.
d = cos(pi*mAngle / 180);
// multiply the above two
ASDoubleMatrixConcat (&rotateMatrix, &textMatrix, &rotateMatrix);
// finally, scale
textMatrix.
a = mFontSize; // x scale
textMatrix.
b = 0; // rotate & skew
textMatrix.
c = 0; // rotate & skew
textMatrix.
d = mFontSize; // y scale
textMatrix.
h = 0; // x translation
textMatrix.
v = 0; // y translation
// multiply the above two to get final matrix.
ASDoubleMatrixConcat (&textMatrix, &rotateMatrix, &textMatrix);
DURING
// Create a new PDEText element and add a kPDETextRun object to it.
pdeText =
PDETextCreate();
PDETextAddEx (pdeText,
kPDETextRun, 0, (
Uns8 *)text, strlen( text ),
pdeFont, &gState, sizeof (gState),
NULL, 0, &textMatrix,
NULL);
// create a new container
PDEContainer pdeContainer =
PDEContainerCreate(
ASAtomFromString( "Watermark" ),
NULL, false );
PDEContent textContent =
PDEContentCreate();
// add the text to the container
PDEContentAddElem( textContent,
kPDEAfterLast, (
PDEElement)pdeText );
PDEContainerSetContent( pdeContainer, textContent );
//if not all pages, just use first
int nNumPage = 0;
if (mPage == ALL_PAGES)
nNumPage =
PDDocGetNumPages( pdDoc );
for ( int iPg=0; iPg < nNumPage; iPg++) {
// acquire each page
pdPage =
PDDocAcquirePage( pdDoc, iPg );
// Acquire the PDEContent associated with the page.
pdeContent = PDPageAcquirePDEContent( pdPage, 0 );
// Insert container into page content.
PDEContentAddElem( pdeContent,
kPDEAfterLast, (
PDEElement)pdeContainer );
// Insert text element into page content.
//PDEContentAddElem (pdeContent, kPDEAfterLast, (PDEElement)pdeText);
// Commit the changes to the PDEContent.
PDPageSetPDEContent( pdPage, 0 );
//Release everything
PDPageReleasePDEContent( pdPage, 0 );
PDPageRelease( pdPage );
// Advertise that we changed the contents so the viewer redraws the
// page and other clients can re-acquire the page contents if needed.
PDPageNotifyContentsDidChange( pdPage );
}
PDERelease( (
PDEObject) textContent);
PDERelease( (
PDEObject) pdeContainer);
HANDLER
// Store the error code.
errorCode = ASGetExceptionErrorCode();
END_HANDLER
// Release any objects we may have created or acquired.
// Note : PDERelease correctly handles NULL, so we don't
// need to test for valid objects.
PDERelease( (
PDEObject) pdeText );
PDERelease( (
PDEObject) pdeColorSpace );
PDERelease( (
PDEObject) pdeFont );
if (pdeExtGState) {
PDERelease((
PDEObject) pdeExtGState);
pdeExtGState =
NULL;
}
if (pdeContent)
PDPageReleasePDEContent( pdPage, 0 );
// If we were thrown an error, let the user know.
if (errorCode) {
ASGetErrorString( ASGetExceptionErrorCode(), errorMsg, 256 );
}
return true ;
}
/* CalculateTextPosition
** ------------------------------------------------------
** calculate position of the text centered.
** IN: char* text, PDEFont font, int tSize, double theta,PDEGraphicState gState.
** OUT: int* px, int* py.
*/
static void CalculateTextPosition( const char * text,
PDEFont font,
int tSize, double theta,
PDEGraphicState gState,
int * px, int * py)
{
// text matrix
ASDoubleMatrix textMatrix;
memset( &textMatrix, 0, sizeof (textMatrix) );
textMatrix.
a = tSize; // x scale
textMatrix.
b = 0; // rotate & skew
textMatrix.
c = 0; // rotate & skew
textMatrix.
d = tSize; // y scale
textMatrix.
h = 0; // x translation
textMatrix.
v = 0; // y translation
// create a text
PDEText pdeText =
PDETextCreate();
PDETextAddEx( pdeText,
kPDETextRun, 0, (
Uns8 *)text, strlen( text ),
font, &gState, sizeof (gState),
NULL, 0, &textMatrix,
NULL );
// get text bound box
ASFixedRect bbox;
PDETextGetBBox( pdeText,
kPDETextRun, 0, &bbox );
double l =
ASFixedToFloat( bbox.
left );
double r =
ASFixedToFloat( bbox.
right );
double t =
ASFixedToFloat( bbox.
top );
double b =
ASFixedToFloat( bbox.
bottom );
// calculation
double beta = atan2( t-b, r-l );
double alhpa = beta + theta;
double ll = sqrt( (t-b)*(t-b) + (r-l)*(r-l) );
*px = int (0.5 * ll * cos( alhpa ) );
*py = int (0.5 * ll * sin( alhpa ) );
// clean
PDERelease( (
PDEObject) pdeText );
}