/*
//
// ADOBE SYSTEMS INCORPORATED
// Copyright (C) 2000-2007 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.
//
// Project: Re-encoding embedded image XObject with JPXDecode filter
//
// This sample demonstrates the process of re-encoding PDF embedded
// image XObjects with the JPEG2000 encoding standard via the use of
// PDFEdit and COS layer APIs.
//
// The output with re-encoded image XObject is saved in the project
// folder as "out.pdf"
//
*/
#ifdef WIN_PLATFORM
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "
CosCalls.h"
#include "
PERCalls.h"
#include "
PEWCalls.h"
#include "PagePDECntCalls.h"
#include "MyPDFLibUtils.h"
#ifdef MAC_PLATFORM
#include "MacUtils.h"
#endif
//
// Switch the INPUT macro definition to cottage.pdf to invoke the code path
// that handles Indexed color space used in the flate-encoded source image.
//
#define INPUT "../sources/ducky.pdf"
//#define INPUT "../sources/cottage.pdf"
PDEImage GetJPXEncodedImage(
PDDoc dstDoc,
PDDoc srcDoc);
void releaseMemory(
PDPage pdPage,
ASStm asStm);
PDEImage GetJPXEncodedImage(
PDDoc dstDoc,
PDDoc srcDoc)
{
PDEImage desImage =
NULL; // PDEImage object to be created
PDEImageAttrs srcImageAttrs; // source image attributes
PDEColorSpace srcColorSpace; // source image color model and values
ASDoubleMatrix srcMatrix; // source image transformation matrix
ASErrorCode errCode = 0;
PDPage srcPage =
NULL;
ASStm srcStm =
NULL;
DURING
// Get source image from input file
srcPage =
PDDocAcquirePage(srcDoc, 0);
PDEContent srcContent = PDPageAcquirePDEContent(srcPage, 0);
int numElems =
PDEContentGetNumElems(srcContent);
PDEElement srcElem =
NULL;
PDEImage srcImage =
NULL;
ASBool found = false ;
//
// Enumerate the content elements to find an image XObject.
// For demonstration purpose, we deal only with the first image XObject found
//
for ( int i = 0; i<numElems; i++)
{
srcElem =
PDEContentGetElem(srcContent, i);
// Make sure we are getting an image XObject
if (
PDEObjectGetType((
PDEObject)srcElem) ==
kPDEImage
&&
PDEImageIsCosObj((
PDEImage)srcElem))
{
srcImage = (
PDEImage)srcElem;
found = true ;
break ;
}
}
if (!found)
{
printf( "No image XObjects found on the first page of the input document.\n \
Try another document.\n" );
releaseMemory(srcPage, srcStm);
E_RETURN(
NULL);
}
// Get the decoded data stream from the image XObject
srcStm =
PDEImageGetDataStm(srcImage, 0);
// Get source image attributes, color space information, and transformation matrix
PDEImageGetAttrs(srcImage, &srcImageAttrs, sizeof (
PDEImageAttrs));
srcColorSpace =
PDEImageGetColorSpace(srcImage);
PDEElementGetMatrixEx((
PDEElement)srcImage, &srcMatrix);
PDEFilterArray filterArray; // Structure to specify filter information for data streams
PDEFilterSpec filterSpec; // Structure to store filter elements in a filter array
CosDoc cosDoc;
CosObj jpxParams; // Dictionay of parameters passed to the JPX encoder
cosDoc =
PDDocGetCosDoc(dstDoc);
jpxParams =
CosNewDict( cosDoc, false , 15);
// width and height of image in pixels
CosDictPut(jpxParams,
ASAtomFromString( "Width" ),
CosNewInteger( cosDoc, false , srcImageAttrs.
width));
CosDictPut(jpxParams,
ASAtomFromString( "Height" ),
CosNewInteger( cosDoc, false , srcImageAttrs.
height));
// width and height of tiles to use in compression; 256 x 256 is typical
CosDictPut(jpxParams,
ASAtomFromString( "TileWidth" ),
CosNewInteger( cosDoc, false , 256));
CosDictPut(jpxParams,
ASAtomFromString( "TileHeight" ),
CosNewInteger( cosDoc, false , 256));
// Should the decorrelation transform be used or not. For best results this is set to true for
// RGB, for LAB false, and for CMYK true may yield better compression.
CosDictPut(jpxParams,
ASAtomFromString( "ColorTransform" ),
CosNewBoolean( cosDoc, false , false ));
// Quality is a value from 1 to 100.
CosDictPut(jpxParams,
ASAtomFromString( "Quality" ),
CosNewInteger( cosDoc, false , 75));
// If lossless compression is specified, the Quality number is ignored.
CosDictPut(jpxParams,
ASAtomFromString( "EncodeLosslessly" ),
CosNewBoolean( cosDoc, false , false ));
// The number of compression resolutions to place in the data.
// 5 gives good compression, and good decompression performance.
CosDictPut(jpxParams,
ASAtomFromString( "ResProgressionSize" ),
CosNewInteger( cosDoc, false , 5));
//
// The image samples may be indices into a color look-up table
// rather than direct color components. This is signified by a Palette
// entry in the jpxParams.
//
if (
PDEColorSpaceGetName(srcColorSpace) ==
ASAtomFromString( "Indexed" ))
{
// Here we deal with DeviceRGB base color space
if (
PDEColorSpaceGetBase(srcColorSpace) ==
ASAtomFromString( "DeviceRGB" ))
{
// Get the number of entries in the color look-up table
ASInt32 sizeLUT =
PDEColorSpaceGetHiVal(srcColorSpace) + 1;
ASInt32 baseNumComps =
PDEColorSpaceGetBaseNumComps(srcColorSpace);
// Obtain the color look-up table
ASUns8* bufLUT = (
ASUns8*)
ASmalloc(sizeLUT * baseNumComps);
PDEColorSpaceGetCTable (srcColorSpace, bufLUT);
//
// The Palette entry is an array. The first entry is an integer giving
// the size of the look-up table in terms of the number of entries.
// The second Palette entry is also an integer and gives the bit depth
// of the entries generated by the table. The remaining entries in
// Palette are strings giving the bytes making up the look-up table.
// There is one string for each component in the color space on which
// The palette is based. This may be any of the color spaces described next.
//
// Decomposing the color table entries (in the pattern of
// RGB...RGB...RGB...) into RRR..., GGG..., and BBB... strings
ASUns8* rCompStr = (
ASUns8*)
ASmalloc(sizeLUT);
ASUns8* gCompStr = (
ASUns8*)
ASmalloc(sizeLUT);
ASUns8* bCompStr = (
ASUns8*)
ASmalloc(sizeLUT);
for ( int i=0, j=0; i<sizeLUT; i++, j+=baseNumComps)
{
rCompStr[i] = bufLUT[j];
gCompStr[i] = bufLUT[j+1];
bCompStr[i] = bufLUT[j+2];
}
ASfree(bufLUT);
// Composing the Palette array
CosObj palette =
CosNewArray( cosDoc, false , baseNumComps + 2);
CosArrayPut( palette, 0,
CosNewInteger( cosDoc, false , sizeLUT));
CosArrayPut( palette, 1,
CosNewInteger( cosDoc, false , srcImageAttrs.
bitsPerComponent));
CosObj rComp =
CosNewString(cosDoc, false , ( char *)rCompStr, sizeLUT);
CosObj gComp =
CosNewString(cosDoc, false , ( char *)gCompStr, sizeLUT);
CosObj bComp =
CosNewString(cosDoc, false , ( char *)bCompStr, sizeLUT);
CosArrayPut( palette, 2, rComp);
CosArrayPut( palette, 3, gComp);
CosArrayPut( palette, 4, bComp);
ASfree(rCompStr);
ASfree(gCompStr);
ASfree(bCompStr);
CosDictPut( jpxParams,
ASAtomFromString( "Palette" ), palette);
// These two entries, BitsPerComponent and Colors, describe the image samples
// to the JPX compressor. Colors is the number of color components.
// In the case of indexed color space, Colors has a value of 1 indicating that
// there is only one channel of data (the indices).
// BitsPerComponent gives the number of components in the indices
// - either 8 or 16. The look-up table may contain up to 1024 entries.
CosDictPut(jpxParams,
ASAtomFromString( "BitsPerComponent" ),
CosNewInteger( cosDoc, false , srcImageAttrs.
bitsPerComponent));
CosDictPut(jpxParams,
ASAtomFromString( "Colors" ),
CosNewInteger( cosDoc, false , 1));
//
// The supported JPEG2000 enumerated color space values:
//
// 12 - CMYK
// 14 - LAB
// 16 - sRGB
// 17 - grayscale
// 18 - sYCC
// 20 - e-sRGB
// 21 - ROMMRGB
// 24 - e-sYCC
//
// only one color spec being provided here
CosObj colorSpecs =
CosNewArray( cosDoc, false , 1);
CosObj aColorSpec =
CosNewDict( cosDoc, false , 1);
CosArrayPut( colorSpecs, 0, aColorSpec);
// The Method key specifies the base color space of the Indexed color space
CosDictPut( aColorSpec,
ASAtomFromString( "Method" ),
CosNewInteger( cosDoc, false , 16));
CosDictPut( jpxParams,
ASAtomFromString( "ColorSpace" ), colorSpecs);
} else {
printf( "We don't deal with Indexed color spaces with base color space other than /DeviceRGB here.\n" );
releaseMemory(srcPage, srcStm);
E_RETURN(
NULL);
}
} else {
//
// We handle non-indexed color spaces here
//
// These two entries, BitsPerComponent and Colors, describe the image samples
// to the JPX compressor. Colors is the number of color components.
CosDictPut(jpxParams,
ASAtomFromString( "BitsPerComponent" ),
CosNewInteger( cosDoc, false , srcImageAttrs.
bitsPerComponent));
CosDictPut(jpxParams,
ASAtomFromString( "Colors" ),
CosNewInteger( cosDoc, false ,
PDEColorSpaceGetNumComps(srcColorSpace)));
CosObj colorSpecs =
CosNewArray( cosDoc, false , 1);
CosObj aColorSpec =
CosNewDict( cosDoc, false , 1);
CosArrayPut( colorSpecs, 0, aColorSpec);
//
// We specify 16 for the /Method key for DeviceRGB source image color space.
// For other source color space, refer to the color space values listed above.
// For instance, for source image in CMYK color space, specify 12 instead.
//
CosDictPut( aColorSpec,
ASAtomFromString( "Method" ),
CosNewInteger( cosDoc, false , 16));
CosDictPut( jpxParams,
ASAtomFromString( "ColorSpace" ), colorSpecs);
}
// Fill in values for the PDEFilterSpec object
memset (&filterSpec, 0, sizeof (
PDEFilterSpec));
filterSpec.
padding = 0;
filterSpec.
encodeParms = jpxParams;
filterSpec.
decodeParms =
CosNewNull();
filterSpec.
name =
ASAtomFromString ( "JPXDecode" );
// Fill in values for the PDEFilterArray object
filterArray.
numFilters = 1;
filterArray.
spec[0] = filterSpec;
// Create the destination image XObject by passing in source image data stream,
// image attributes, and JPXDecode filter information
desImage =
PDEImageCreateEx(&srcImageAttrs, sizeof (srcImageAttrs),
&srcMatrix, 0, srcColorSpace,
NULL, &filterArray, srcStm,
NULL, 0);
CosObj obj;
PDEImageGetCosObj( desImage, &obj);
// For JPX images this dictionary entries is optional;
// Remove so that the color space specified in the JPEG2000
// data is used
CosDictRemove( obj,
ASAtomFromString( "ColorSpace" ));
// For JPX images this is never consulted; remove it
CosDictRemove( obj,
ASAtomFromString( "BitsPerComponent" ));
HANDLER
errCode =
ERRORCODE;
END_HANDLER
// Do some clean-up before returning the PDEImage object
releaseMemory(srcPage, srcStm);
if (errCode)
ASRaise(errCode);
return desImage;
}
void releaseMemory(
PDPage pdPage,
ASStm asStm)
{
if (asStm)
ASStmClose(asStm);
if (pdPage)
{
PDPageReleasePDEContent(pdPage,
NULL);
PDPageRelease(pdPage);
}
}
void MainProc( void );
void MainProc( void )
{
ASBool b;
PDDoc pdDoc =
NULL; // reference to the output PDF document
PDDoc sourceDoc =
NULL; // reference to the input PDF document
PDPage pdPage =
NULL; // reference to the page object in pdDoc
PDEContent pdeContent; // container for page content
ASFixedRect mediaBox; // dimensions of page
PDEImage pdeImage =
NULL; // reference to the re-encoded image object
ASErrorCode errCode = 0;
DURING
// Create new document
pdDoc =
PDDocCreate();
// Set the media box of the new document pages.
mediaBox.
left =
fixedZero;
mediaBox.
top =
Int16ToFixed(11*72);
mediaBox.
right =
Int16ToFixed(8.5*72);
mediaBox.
bottom =
fixedZero;
// Create page with the mediabox and insert as first page
pdPage =
PDDocCreatePage(pdDoc,
PDBeforeFirstPage, mediaBox);
sourceDoc = MyPDDocOpen(INPUT);
// Acquire PDEContent container for page
pdeContent = PDPageAcquirePDEContent(pdPage,
NULL);
// Calls the helper function to re-encode the source image data
pdeImage = GetJPXEncodedImage(pdDoc, sourceDoc);
if (pdeImage)
{
// insert image into page content
PDEContentAddElem(pdeContent,
kPDEAfterLast, (
PDEElement)pdeImage);
// Set the PDEContent for the page
b = PDPageSetPDEContent(pdPage, 0);
PDERelease((
PDEObject)pdeImage);
// save document to a file
#if !MAC_ENV
ASPathName path =
ASFileSysCreatePathName (
ASGetDefaultFileSys(),
ASAtomFromString( "Cstring" ), "out.pdf" ,
NULL);
PDDocSave(pdDoc,
PDSaveFull |
PDSaveLinearized, path,
ASGetDefaultFileSys(), 0, 0);
ASFileSysReleasePath(
ASGetDefaultFileSys(), path);
#else
ASPathName macPath = GetMacPath( "out.pdf" );
PDDocSave(pdDoc,
PDSaveFull |
PDSaveLinearized, macPath,
ASGetDefaultFileSys(),
NULL,
NULL);
ASFileSysReleasePath(
ASGetDefaultFileSys(),macPath);
#endif
}
HANDLER
errCode =
ERRORCODE;
END_HANDLER
DisplayErrorAndWarnings(sourceDoc, errCode);
releaseMemory(pdPage,
NULL);
if (pdDoc)
PDDocClose(pdDoc);
if (sourceDoc)
PDDocClose(sourceDoc);
}
#define INCLUDE_MYPDFLIBAPP_CPP 1
#include "MyPDFLibApp.cpp"
#undef INCLUDE_MYPDFLIBAPP_CPP