/*
//
//   ADOBE SYSTEMS INCORPORATED
//   Copyright (C) 2000-2002 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.
//
*/
#ifndef MAC_PLATFORM
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#endif

#include "MyPDFLibUtils.h"
#include "ASCalls.h"
#include "PDCalls.h"
#include "PDFLCalls.h"
#include "PERCalls.h"
#include "PEWCalls.h"
#include "CosCalls.h"
#include "ASExtraCalls.h"

#ifdef MAC_ENV
#include "MacUtils.h"
#endif

// Use appropriate relative path for input file
// This one works for running from Win IDE and Mac build location
#define INPUT_FILE           "../sources/drawtomemory.pdf"

// It rounds off double precision values to nearest Int32 value.
#define ROUND(x) ((ASInt32)((x > 0)?(x+0.5):(x-0.5)))

static   ASAtom   sDeviceRGB_K,  sDeviceCMYK_K,  sDeviceGray_K;

static   void   SetContentToPage(PDPage  pdPage,  PDEContent  content)
{
        CosObj  pageObj =  PDPageGetCosObj(pdPage);
        CosDoc  dP =  CosObjGetDoc(pageObj);
        CosObj  contObj, rsrcObj;

                PDEContentToCosObj(content,  kPDEContentToPage, 0, 0, dP, 0,
                                             &contObj, &rsrcObj);

                //
                // Place content and resource objects into page
                //

                CosDictPut(pageObj,  ASAtomFromString( "Contents" ), contObj);
                CosDictPut(pageObj,  ASAtomFromString( "Resources" ), rsrcObj);
}

static   void   MainProc()
{
                ASInt32  err = 0;

                //
                // Initialize frequently used atoms.
                //

                sDeviceRGB_K    =  ASAtomFromString( "DeviceRGB" );
                sDeviceCMYK_K  =  ASAtomFromString( "DeviceCMYK" );
                sDeviceGray_K  =  ASAtomFromString( "DeviceGray" );

                char  *buffer =  NULL;

                PDDoc  pdDoc =  MyPDDocOpen(INPUT_FILE);
                if  (pdDoc)
               {
                                PDPage  pdPage =  PDDocAcquirePage(pdDoc, 0);

                                DURING
                                                ASFixedMatrix  fixedMatrix;
                                                ASDoubleMatrix  dblMatrix;
                                                ASFixedRect  fixedDestRect, fixedPageRect;
                                                ASDoubleRect  dblDestRect;

                                                PDPageGetFlippedMatrix(pdPage, &fixedMatrix);
                                                FixedToDoubleMatrix(&dblMatrix, &fixedMatrix);

                                                PDPageGetCropBox(pdPage, &fixedDestRect);
                                                FixedToDoubleRect(&dblDestRect, &fixedDestRect);

                                               dblMatrix.v  += dblDestRect.bottom;
                                               dblMatrix.h  += dblDestRect.left;

                                               fixedPageRect.left  = fixedPageRect.bottom  = 0;
                                               fixedPageRect.right  = fixedDestRect.right  - fixedDestRect.left;
                                               fixedPageRect.top  = fixedDestRect.top  - fixedDestRect.bottom;
                                               
                                                ASInt32  bpc = 8;
                                                ASAtom    csAtom =  sDeviceRGB_K;

                                                ASCab  flags =  ASCabNew();
                                                ASCabPutBool(flags, kPDPageDoLazyEraseStr,  true );
                                               
                                                ASInt32  bufferSize = PDPageDrawContentsToMemoryEx(
                                                                                                                                               pdPage,
                                                                                                                                               flags,
                                                                                                                                               &dblMatrix,  NULL,
                                                                                                                                               csAtom,
                                                                                                                                               bpc,
                                                                                                                                               &dblDestRect,
                                                                                                                                                NULL,
                                                                                                                                               0,
                                                                                                                                                NULLNULL);
                                                //
                                                // Now allocate buffer 
                                                //

                                               buffer = ( char *) malloc(bufferSize);
                                               memset(buffer, 0xff, bufferSize);

                                                //
                                                // Render page content to the bitmap buffer
                                                //

                                                ASCabPutBool(flags, kPDPageUseAnnotFacesStr,  true );
                                                ASCabPutBool(flags, kPDPageDrawSmoothTextStr,  true );
                                                ASCabPutBool(flags, kPDPageDrawSmoothLineArtStr,  true );
                                                ASCabPutBool(flags, kPDPageDrawSmoothImageStr,  true );

                                               PDPageDrawContentsToMemoryEx(
                                                                                                                                               pdPage,
                                                                                                                                               flags,
                                                                                                                                               &dblMatrix,  NULL,
                                                                                                                                               csAtom,
                                                                                                                                               bpc,
                                                                                                                                               &dblDestRect,
                                                                                                                                               buffer,
                                                                                                                                               bufferSize,
                                                                                                                                                NULLNULL);

                                                const   char  *fileName =  "out.pdf" ;

                                                volatile   ASPathName  outputPathName =  NULL;
                                                volatile   PDDoc            outputPDDoc       =  NULL;
                                                volatile   PDPage          outputPDPage     =  NULL;
                                                volatile   PDEContent  content               =  NULL;
                                                volatile   PDEImage      image                   =  NULL;
                                                volatile   PDEColorSpace  cs                   =  NULL;

                                                DURING
                                                               outputPDDoc   =  PDDocCreate();
                                                               outputPDPage =  PDDocCreatePage(outputPDDoc,  PDBeforeFirstPage, fixedPageRect);
                                                               content           =  PDEContentCreate();

                                                                PDEImageAttrs  attrs;
                                                               memset(&attrs, 0,  sizeof (attrs));
                                                               attrs.flags  =  kPDEImageExternal;
                                                               attrs.height  = abs(ROUND(dblDestRect.top) -  ROUND(dblDestRect.bottom));
                                                               attrs.width  = abs(ROUND(dblDestRect.right) -  ROUND(dblDestRect.left));

                                                                ASInt32  nComps = 1;
                                                                if  (csAtom ==  sDeviceGray_K)
                                                                               nComps = 1;
                                                                else   if  (csAtom ==  sDeviceRGB_K)
                                                                               nComps = 3;
                                                                else
                                                                               nComps = 4;

                                                                // 
                                                                // The bitmap data generated by PDPageDrawContentsToWindow is 32-bit aligned. 
                                                                // The PDF image operator expects, however, 8-bit aligned image data. 
                                                                // To remedy this difference, we check to see if the 32-bit aligned width
                                                                // is different from the 8-bit aligned width. If so, we fix the image data by 
                                                                // stripping off the padding at the end
                                                                //

                                                                if  (((((attrs.width  * bpc * nComps) + 31) / 32) * 4) != ((attrs.width  * bpc * nComps) / 8))
                                                               {
                                                                                char  *src, *dest;                              // temporary pointers to the bitmap data buffer 
                                                                                                                                                                                                                                                // created by PDPageDrawContentsToMemory
                                                                                int  sw, dw;                                                                         

                                                                               sw = ((((attrs.width  * bpc * nComps) + 31) / 32) * 4);
                                                                               dw = (attrs.width  * bpc * nComps) / 8;
                                                                               src = dest = buffer;

                                                                                //
                                                                                // Copy the source bytes to the destination
                                                                                //

                                                                                for  ( int  i = 0; i < attrs.height; i++) {
                                                                                                for  ( int  j = 0; j < dw; j++) 
                                                                                                               dest[j] = src[j];
                                                                                               src += sw; dest += dw;
                                                                               }
                                                                               
                                                                                //
                                                                                // Recalculate buffer size
                                                                                //

                                                                               bufferSize = dw * attrs.height;
                                                               } 
                                                                else
                                                               {
                                                                               attrs.width  = (((( attrs.width* bpc * nComps) + 31) / 32) * 4) * 8 / (bpc * nComps);
                                                               }
                                                               attrs.bitsPerComponent  = bpc;
                                                                PDEFilterArray  filterArray;
                                                               memset(&filterArray, 0,  sizeof (filterArray));
                                                               filterArray.numFilters  = 1;
                                                               filterArray.spec[0].name  =  ASAtomFromString( "FlateDecode" );

                                                                ASDoubleMatrix  imageDblMatrix;
                                                               imageDblMatrix.a  = attrs.width;
                                                               imageDblMatrix.d  = attrs.height;
                                                               imageDblMatrix.b  = imageDblMatrix.c  = 0;
                                                               imageDblMatrix.h  = imageDblMatrix.v  = 0;

                                                               cs =  PDEColorSpaceCreateFromName(csAtom);

                                                                //
                                                                // Create an image XObject from the bitmap buffer to embed in the output document
                                                                //

                                                               image =  PDEImageCreateEx(
                                                                                                               &attrs,  sizeof (attrs),
                                                                                                               &imageDblMatrix, 0,
                                                                                                               cs,  NULL,
                                                                                                               &filterArray, 0,
                                                                                                               ( unsigned   char *) buffer, bufferSize);
                                                                PDEContentAddElem(content, 0, (PDEElement) image);
                                                                SetContentToPage(outputPDPage, content);

                                                               #if WIN_PLATFORM || UNIX_PLATFORM
                                                                               outputPathName =  ASFileSysCreatePathName(NULLASAtomFromString( "Cstring" ), fileName, 0);
                                                               #elif MAC_PLATFORM
                                                                               outputPathName =  GetMacPath(fileName);
                                                               #endif

                                                                                PDDocSave(outputPDDoc,  PDSaveFull  |  PDSaveLinearized  |  PDSaveCollectGarbage, outputPathName, 0, 0, 0);
                                                HANDLER
                                                               err =  ERRORCODE;
                                                END_HANDLER

                                                PDERelease((PDEObject) cs);
                                                PDERelease((PDEObject) image);
                                                PDERelease((PDEObject) content);

                                                if  (outputPathName)
                                                                ASFileSysReleasePath(0, outputPathName);
                                                if  (outputPDPage)
                                                                PDPageRelease(outputPDPage);
                                                if  (outputPDDoc)
                                                                PDDocClose(outputPDDoc);

                                HANDLER
                                               err =  ERRORCODE;
                                END_HANDLER

                                DisplayErrorAndWarnings(pdDoc, err);

                                if  (pdPage)
                                                PDPageRelease(pdPage);
                                if  (buffer)
                                               free(buffer);

                                PDDocClose(pdDoc);
               }
}


#define INCLUDE_MYPDFLIBAPP_CPP 1
#include "MyPDFLibApp.cpp"
#undef INCLUDE_MYPDFLIBAPP_CPP