|
|
/////////////////////////////////////////////////////////// |
|
|
// Page.cpp |
|
|
// Implementation of the Class Page |
|
|
// Created on: 19-<EFBFBD><EFBFBD><EFBFBD>-2009 12:27:56 |
|
|
/////////////////////////////////////////////////////////// |
|
|
|
|
|
#include "Page.h" |
|
|
#include "Document.h" |
|
|
|
|
|
#include "ContentHandler.h" |
|
|
#include "Exception.h" |
|
|
#include "MediaBoxElementHandler.h" |
|
|
#include "CropBoxElementHandler.h" |
|
|
#include "TypeElementHandler.h" |
|
|
#include "RemoveHimSelfHandler.h" |
|
|
#include "AnnotsHandler.h" |
|
|
#include "RotationHandler.h" |
|
|
#include "FlateDecode.h" |
|
|
#include "Utils.h" |
|
|
#include "Rectangle.h" |
|
|
#include "Filter.h" |
|
|
#include <iostream> |
|
|
#include <string.h> |
|
|
#include "Parser.h" |
|
|
|
|
|
using namespace merge_lib; |
|
|
|
|
|
|
|
|
Page::Page(unsigned int pageNumber): _pageNumber(pageNumber),_root(NULL), _rotation(0) |
|
|
{ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Page::~Page() |
|
|
{ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
std::string & Page::getPageContent() |
|
|
{ |
|
|
return _root->getObjectContent(); |
|
|
} |
|
|
|
|
|
const Object::Children & Page::getPageRefs() |
|
|
{ |
|
|
return _root->getChildren(); |
|
|
} |
|
|
|
|
|
|
|
|
void Page::recalculateObjectNumbers(unsigned int & newNumber) |
|
|
{ |
|
|
_root->recalculateObjectNumbers(newNumber); |
|
|
} |
|
|
|
|
|
Object * Page::pageToXObject(std::vector<Object *> & allObjects, std::vector<Object *> & annots, bool isCloneNeeded) |
|
|
{ |
|
|
Object * xObject = (isCloneNeeded) ? _root->getClone(allObjects) : _root; |
|
|
return _pageToXObject(xObject, annots); |
|
|
} |
|
|
|
|
|
|
|
|
Object * Page::_pageToXObject(Object *& page, std::vector<Object *> & annots) |
|
|
{ |
|
|
RemoveHimselfHandler * removeParent = new RemoveHimselfHandler(page, "/Parent"); |
|
|
RemoveHimselfHandler * removeBleedBox = new RemoveHimselfHandler(page, "/BleedBox"); |
|
|
RemoveHimselfHandler * removeTrimBox = new RemoveHimselfHandler(page, "/TrimBox"); |
|
|
RemoveHimselfHandler * removeArtBox = new RemoveHimselfHandler(page, "/ArtBox"); |
|
|
RemoveHimselfHandler * removeBoxColorInfo = new RemoveHimselfHandler(page, "/BoxColorInfo"); |
|
|
RemoveHimselfHandler * removeRotate = new RemoveHimselfHandler(page, "/Rotate"); |
|
|
RemoveHimselfHandler * removeThumb = new RemoveHimselfHandler(page, "/Thumb"); |
|
|
RemoveHimselfHandler * removeB = new RemoveHimselfHandler(page, "/B"); |
|
|
RemoveHimselfHandler * removeDur = new RemoveHimselfHandler(page, "/Dur"); |
|
|
RemoveHimselfHandler * removeTrans = new RemoveHimselfHandler(page, "/Trans"); |
|
|
AnnotsHandler * removeAnnots = new AnnotsHandler(page, "/Annots", annots); |
|
|
RemoveHimselfHandler * removeAA = new RemoveHimselfHandler(page, "/AA"); |
|
|
RemoveHimselfHandler * removeID = new RemoveHimselfHandler(page, "/ID"); |
|
|
RemoveHimselfHandler * removePZ = new RemoveHimselfHandler(page, "/PZ"); |
|
|
RemoveHimselfHandler * removeSeparationInfo = new RemoveHimselfHandler(page, "/SeparationInfo"); |
|
|
RemoveHimselfHandler * removeTabs = new RemoveHimselfHandler(page, "/Tabs"); |
|
|
RemoveHimselfHandler * removeTemplateInstantiated = new RemoveHimselfHandler(page, "/TemplateInstantiated"); |
|
|
RemoveHimselfHandler * removePresSteps = new RemoveHimselfHandler(page, "/PresSteps"); |
|
|
RemoveHimselfHandler * removeUserUnit = new RemoveHimselfHandler(page, "/UserUnit"); |
|
|
RemoveHimselfHandler * removeVP = new RemoveHimselfHandler(page, "/VP"); |
|
|
ContentHandler * contentHandler = new ContentHandler(page, "/Contents"); |
|
|
CropBoxElementHandler * cropBoxElementHandler = new CropBoxElementHandler(page); |
|
|
MediaBoxElementHandler * mediaBoxElementHandler = new MediaBoxElementHandler(page); |
|
|
TypeElementHandler * typeElementHandler = new TypeElementHandler(page); |
|
|
|
|
|
cropBoxElementHandler->addNextHandler(mediaBoxElementHandler); |
|
|
mediaBoxElementHandler->addNextHandler(removeParent); |
|
|
removeParent->addNextHandler(removeBleedBox); |
|
|
removeBleedBox->addNextHandler(removeTrimBox); |
|
|
removeTrimBox->addNextHandler(removeArtBox); |
|
|
removeArtBox->addNextHandler(removeBoxColorInfo); |
|
|
removeBoxColorInfo->addNextHandler(removeRotate); |
|
|
removeRotate->addNextHandler(removeThumb); |
|
|
removeThumb->addNextHandler(removeB); |
|
|
removeB->addNextHandler(removeDur); |
|
|
removeDur->addNextHandler(removeTrans); |
|
|
removeTrans->addNextHandler(removeAnnots); |
|
|
removeAnnots->addNextHandler(removeAA); |
|
|
removeAA->addNextHandler(removeID); |
|
|
removeID->addNextHandler(removePZ); |
|
|
removePZ->addNextHandler(removeSeparationInfo); |
|
|
removeSeparationInfo->addNextHandler(removeTabs); |
|
|
removeTabs->addNextHandler(removeTemplateInstantiated); |
|
|
removeTemplateInstantiated->addNextHandler(removePresSteps); |
|
|
removePresSteps->addNextHandler(removeUserUnit); |
|
|
removeUserUnit->addNextHandler(removeVP); |
|
|
removeVP->addNextHandler(typeElementHandler); |
|
|
typeElementHandler->addNextHandler(contentHandler); |
|
|
|
|
|
cropBoxElementHandler->processObjectContent(); |
|
|
cropBoxElementHandler->changeObjectContent(); |
|
|
|
|
|
delete cropBoxElementHandler; |
|
|
return page; |
|
|
} |
|
|
|
|
|
|
|
|
std::string _getContentOfContentObject(MergePageDescription & description) |
|
|
{ |
|
|
std::string content("<<\n/Length "); |
|
|
std::string stream = ""; |
|
|
if(!description.skipBasePage) |
|
|
{ |
|
|
stream.append("1.000000 0 0 1.000000 0 0 cm\n" |
|
|
"q\n"); |
|
|
stream.append(description.basePageTransformation.getCMT()); |
|
|
stream.append("/OriginalPage2 Do\n" |
|
|
"Q\n"); |
|
|
|
|
|
} |
|
|
if(!description.skipOverlayPage) |
|
|
{ |
|
|
stream.append("1.000000 0 0 1.000000 0 0 cm\n" |
|
|
"q\n"); |
|
|
stream.append(description.overlayPageTransformation.getCMT()); |
|
|
stream.append("/OriginalPage1 Do\n" |
|
|
"Q\n"); |
|
|
} |
|
|
FlateDecode encoder; |
|
|
encoder.encode(stream); |
|
|
content.append(Utils::uIntToStr(stream.size())); |
|
|
content.append("\n/Filter /FlateDecode\n>>\nstream\n"); |
|
|
content.append(stream); |
|
|
content.append("endstream\n"); |
|
|
return content; |
|
|
} |
|
|
|
|
|
void _recalculateAnnotsCoordinates(Object * annotation, |
|
|
const Rectangle & basePagesRectangle, |
|
|
const Rectangle & outputPagesRectangle, |
|
|
const MergePageDescription & description) |
|
|
{ |
|
|
std::string annotsRectangleName("/Rect"); |
|
|
Object * objectWithRectangle; |
|
|
unsigned int fake; |
|
|
annotation->findObject(annotsRectangleName, objectWithRectangle, fake); |
|
|
std::string annotContent = objectWithRectangle->getObjectContent(); |
|
|
|
|
|
Rectangle annotsRectangle(annotsRectangleName.c_str(), annotContent); |
|
|
|
|
|
//we move annotation from base page to output page |
|
|
//that's way annotation should be scaled before all transformations. |
|
|
//Annotation's coordinates should be recalculated according to new |
|
|
//page width and height |
|
|
|
|
|
annotsRectangle.recalculateInternalRectangleCoordinates(description.basePageTransformation.getAnnotsTransformations()); |
|
|
annotsRectangle.updateRectangle(annotation, " "); |
|
|
} |
|
|
|
|
|
// function updates parent reference of annotation with new page object |
|
|
static void _updateAnnotParentPage(Object *annotation,Object *newParentPage) |
|
|
{ |
|
|
if( annotation ) |
|
|
{ |
|
|
std::string strP = "/P"; |
|
|
std::string &annotContent = annotation->getObjectContent(); |
|
|
|
|
|
size_t startOfP = Parser::findTokenName(annotContent,strP); |
|
|
if( startOfP == std::string::npos ) |
|
|
{ |
|
|
return; |
|
|
} |
|
|
size_t endOfP = Parser::findEndOfElementContent(annotContent,startOfP + strP.size()); |
|
|
|
|
|
// lets find object with reference to parent |
|
|
std::vector<Object *> children = annotation->getChildrenByBounds(startOfP,endOfP); |
|
|
if( children.size() == 0 ) |
|
|
{ |
|
|
return; |
|
|
} |
|
|
|
|
|
Object *childWithP = children[0]; |
|
|
if( childWithP ) |
|
|
{ |
|
|
Object::ReferencePositionsInContent pagePosition = annotation->removeChild(childWithP); |
|
|
annotation->eraseContent(startOfP,endOfP-startOfP); |
|
|
std::stringstream strout; |
|
|
strout <<"/P "<<newParentPage->getObjectNumber()<<" "<<newParentPage->getgenerationNumber()<<" R\n"; |
|
|
// to compensate posible deviation |
|
|
for(size_t i =strout.str().size();i<endOfP-startOfP;i++) |
|
|
{ |
|
|
strout<<" "; |
|
|
} |
|
|
annotation->insertToContent(startOfP,strout.str()); |
|
|
annotation->addChild(newParentPage,pagePosition); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
// function performs adjusting of some color parameters of annotation |
|
|
// to avoid interference with overlay content |
|
|
static void _updateAnnotFormColor(Object *annotation ) |
|
|
{ |
|
|
std::string &objectContent = annotation->getObjectContent(); |
|
|
if( objectContent.find("/Widget") == std::string::npos ) |
|
|
{ |
|
|
return; |
|
|
} |
|
|
size_t startOfAP = Parser::findTokenName(objectContent,"/AP"); |
|
|
if( startOfAP == std::string::npos ) |
|
|
{ |
|
|
return; |
|
|
} |
|
|
size_t endOfAP = objectContent.find(">>", startOfAP); |
|
|
std::vector<Object *> aps = annotation->getChildrenByBounds(startOfAP, endOfAP); |
|
|
for(size_t i = 0; i < aps.size(); ++i) |
|
|
{ |
|
|
Object * childWithAP = aps[i]; |
|
|
if( !childWithAP->hasStream() ) |
|
|
{ |
|
|
continue; |
|
|
} |
|
|
// first lets obtain and decode stream of Annotation appearrence stream |
|
|
std::string & content = childWithAP->getObjectContent(); |
|
|
|
|
|
Filter filter(childWithAP); |
|
|
std::string decodedStream; |
|
|
filter.getDecodedStream(decodedStream); |
|
|
|
|
|
// lets iterate over stream and find operator f and remove it! |
|
|
size_t beg = 0; |
|
|
size_t found = 0; |
|
|
std::string token; |
|
|
while(Parser::getNextWord(token,decodedStream,beg,&found)) |
|
|
{ |
|
|
if( token == "f" || token == "F" ) |
|
|
{ |
|
|
if( found != std::string::npos ) |
|
|
{ |
|
|
decodedStream[found] = ' '; |
|
|
} |
|
|
break; |
|
|
} |
|
|
} |
|
|
// Then we need to update Filter section (if any) |
|
|
std::string filterStr = "/Filter"; |
|
|
size_t startOfFlate = Parser::findTokenName(content,filterStr); |
|
|
if( startOfFlate != std::string::npos ) |
|
|
{ |
|
|
size_t endOfFlate = Parser::findEndOfElementContent(content,startOfFlate+filterStr.size()); |
|
|
childWithAP->eraseContent(startOfFlate,endOfFlate-startOfFlate); |
|
|
//encode and put new stream to object content |
|
|
childWithAP->insertToContent(startOfFlate,"/Filter /FlateDecode "); |
|
|
FlateDecode flate; |
|
|
flate.encode(decodedStream); |
|
|
} |
|
|
|
|
|
// update the length field |
|
|
std::string lengthStr = "/Length"; |
|
|
size_t startOfLength = Parser::findTokenName(content,lengthStr,0); |
|
|
if( startOfLength != std::string::npos ) |
|
|
{ |
|
|
size_t endOfLength = Parser::findEndOfElementContent(content,startOfLength + lengthStr.size()); |
|
|
childWithAP->eraseContent(startOfLength,endOfLength-startOfLength); |
|
|
std::stringstream ostr; |
|
|
ostr<<"/Length "<< decodedStream.size()<<"\n"; |
|
|
childWithAP->insertToContent(startOfLength,ostr.str()); |
|
|
|
|
|
// update the stream of object with new content |
|
|
std::string stream("stream"); |
|
|
size_t leftBoundOfContentStream = content.find(stream); |
|
|
if( leftBoundOfContentStream != std::string::npos ) |
|
|
{ |
|
|
size_t rightBoundOfContentStream = content.find("endstream", leftBoundOfContentStream); |
|
|
if( rightBoundOfContentStream == std::string::npos ) |
|
|
{ |
|
|
rightBoundOfContentStream = content.size() - 1; |
|
|
} |
|
|
childWithAP->eraseContent(leftBoundOfContentStream, rightBoundOfContentStream - leftBoundOfContentStream); |
|
|
decodedStream.insert(0,"\nstream\n"); |
|
|
childWithAP->insertToContent(leftBoundOfContentStream,decodedStream); |
|
|
childWithAP->appendContent("endstream\n"); |
|
|
childWithAP->forgetStreamInFile(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// sometimes page object does not have resources, |
|
|
// they are inherited from parent object |
|
|
// this method processes such cases and insert resources from parent to page |
|
|
// for correct X-Object transformation |
|
|
static void processBasePageResources(Object *basePage) |
|
|
{ |
|
|
if( basePage == NULL ) |
|
|
{ |
|
|
return; |
|
|
} |
|
|
std::string resourceToken = "/Resources"; |
|
|
if( Parser::findTokenName(basePage->getObjectContent(),resourceToken) == std::string::npos ) |
|
|
{ |
|
|
// it seems base page does not have resources, they can be located in parent! |
|
|
Object *resource = basePage->findPatternInObjOrParents(resourceToken); |
|
|
if( resource ) |
|
|
{ |
|
|
std::string &resContStr = resource->getObjectContent(); |
|
|
size_t startOfRes = Parser::findTokenName(resContStr,resourceToken); |
|
|
if( startOfRes == std::string::npos ) |
|
|
{ |
|
|
// no resources at all |
|
|
return; |
|
|
} |
|
|
size_t endOfRes = Parser::findEndOfElementContent(resContStr,startOfRes + resourceToken.size()); |
|
|
if( endOfRes == std::string::npos ) |
|
|
{ |
|
|
return; // broken resources |
|
|
} |
|
|
std::string resourceContent = resContStr.substr(startOfRes,endOfRes-startOfRes); |
|
|
|
|
|
size_t positionToInsert = basePage->getObjectContent().find("<<"); |
|
|
if( positionToInsert == std::string::npos ) |
|
|
{ |
|
|
positionToInsert = 0; |
|
|
resourceContent.insert(0,"<<"); |
|
|
resourceContent.append(">>"); |
|
|
} |
|
|
else |
|
|
{ |
|
|
positionToInsert += strlen("<<"); |
|
|
} |
|
|
// insert obtained resources to base page |
|
|
basePage->insertToContent(positionToInsert,resourceContent); |
|
|
|
|
|
// if resource contains childs, then we need to add reference to them to current object |
|
|
std::vector<Object *> resChilds = resource->getChildrenByBounds(startOfRes, endOfRes); |
|
|
std::vector<Object *>::const_iterator objectIt(resChilds.begin()); |
|
|
|
|
|
const Object::Children & children = resource->getChildren(); |
|
|
|
|
|
for(; objectIt != resChilds.end(); objectIt++ ) |
|
|
{ |
|
|
Object::Children::const_iterator childrenIt = children.find( (*objectIt)->getObjectNumber()); |
|
|
if( childrenIt != children.end() ) |
|
|
{ |
|
|
Object::ReferencePositionsInContent refPositionInCont = (*childrenIt).second.second; |
|
|
|
|
|
Object::ReferencePositionsInContent::iterator positionIt(refPositionInCont.begin()); |
|
|
|
|
|
Object::ReferencePositionsInContent newPositions; |
|
|
for( ;positionIt != refPositionInCont.end(); positionIt++ ) |
|
|
{ |
|
|
newPositions.push_back( (*positionIt) - startOfRes + positionToInsert ); |
|
|
} |
|
|
|
|
|
basePage->addChild( (*objectIt),newPositions ); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
std::string Page::_getMergedPageContent( unsigned int & contentPosition, |
|
|
unsigned int & parentPosition, |
|
|
unsigned int & originalPage1Position, |
|
|
unsigned int & originalPage2Position, |
|
|
std::pair<unsigned int, unsigned int> originalPageNumbers, |
|
|
const MergePageDescription & description, |
|
|
Object * basePage, |
|
|
const std::vector<Object *> & annots, |
|
|
std::vector <Object::ChildAndItPositionInContent> & annotsPositions |
|
|
) |
|
|
{ |
|
|
std::string content("<<\n/Type /Page\n"); |
|
|
content.append("/Contents "); |
|
|
contentPosition = content.size(); |
|
|
//object number 1 will be recalculated during serialization |
|
|
content.append("1 0 R\n"); |
|
|
Rectangle mediaBox("/MediaBox"); |
|
|
mediaBox.x2 = description.outPageWidth; |
|
|
mediaBox.y2 = description.outPageHeight; |
|
|
mediaBox.appendRectangleToString(content, " "); |
|
|
content.append("/Parent "); |
|
|
parentPosition = content.size(); |
|
|
//object number 1 will be recalculated during serialization |
|
|
content.append("1 0 R\n"); |
|
|
content.append("/Resources <<\n" |
|
|
"/ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]\n" |
|
|
"/XObject <<\n"); |
|
|
if(!description.skipOverlayPage) |
|
|
{ |
|
|
content.append("/OriginalPage1 "); |
|
|
originalPage1Position = content.size(); |
|
|
content.append(Utils::uIntToStr(originalPageNumbers.first)); |
|
|
content.append(" 0 R\n"); |
|
|
} |
|
|
if(!description.skipBasePage) |
|
|
{ |
|
|
content.append("/OriginalPage2 "); |
|
|
originalPage2Position = content.size(); |
|
|
content.append(Utils::uIntToStr(originalPageNumbers.second)); |
|
|
content.append(" "); |
|
|
content.append(Utils::uIntToStr(basePage->getgenerationNumber())); |
|
|
content.append(" R\n"); |
|
|
} |
|
|
content.append(">>\n>>\n"); |
|
|
|
|
|
content.append("/Annots [ "); |
|
|
if(!description.skipBasePage) |
|
|
{ |
|
|
Rectangle basePageRectangle("/BBox", basePage->getObjectContent()); |
|
|
for(size_t i = 0; i < annots.size(); ++i) |
|
|
{ |
|
|
_updateAnnotFormColor(annots[i]); |
|
|
_recalculateAnnotsCoordinates(annots[i], basePageRectangle, mediaBox, description); |
|
|
Object::ReferencePositionsInContent annotationPosition; |
|
|
annotationPosition.push_back(content.size()); |
|
|
Object::ChildAndItPositionInContent annotAndItPosition(annots[i], annotationPosition); |
|
|
annotsPositions.push_back(annotAndItPosition); |
|
|
content.append(Utils::uIntToStr(annots[i]->getObjectNumber())); |
|
|
content.append(" "); |
|
|
content.append(Utils::uIntToStr(annots[i]->getgenerationNumber())); |
|
|
content.append(" R "); |
|
|
} |
|
|
} |
|
|
content.append("] \n>>\n"); |
|
|
|
|
|
return content; |
|
|
} |
|
|
|
|
|
void Page::merge(Page * sourcePage, Document * parentDocument, MergePageDescription & description, bool isPageDuplicated) |
|
|
{ |
|
|
if( sourcePage == NULL ) |
|
|
{ |
|
|
description.skipBasePage = true; |
|
|
} |
|
|
if(!description.skipOverlayPage) |
|
|
{ |
|
|
// Lets recalculate final transformation of overlay page |
|
|
// before it will be places into XObject |
|
|
Rectangle mediaBox("/MediaBox",_root->getObjectContent()); |
|
|
description.overlayPageTransformation.recalculateTranslation(mediaBox.getWidth(),mediaBox.getHeight()); |
|
|
|
|
|
std::vector<Object *> fake; |
|
|
_pageToXObject(_root, fake); |
|
|
} |
|
|
|
|
|
std::vector<Object *> toAllObjects; |
|
|
std::vector<Object *> annotations; |
|
|
Object * sourcePageToXObject = 0; |
|
|
if(!description.skipBasePage) |
|
|
{ |
|
|
RotationHandler rotationHandler(sourcePage->_root, "/Rotate", *this); |
|
|
rotationHandler.processObjectContent(); |
|
|
description.basePageTransformation.addRotation(_rotation); |
|
|
|
|
|
if( sourcePage->_root->getObjectContent().find("/Annots") != std::string::npos ) |
|
|
{ |
|
|
Object *crop = sourcePage->_root->findPatternInObjOrParents("/CropBox"); |
|
|
if( crop ) |
|
|
{ |
|
|
// we need to calculate special compensational shifting |
|
|
// for annotations if cropbox is starting not from 0,0 |
|
|
Rectangle mediaBox("/CropBox", crop->getObjectContent()); |
|
|
if( !Utils::doubleEquals(mediaBox.x1,0) || !Utils::doubleEquals(mediaBox.y1,0) ) |
|
|
{ |
|
|
double shiftX = Utils::doubleEquals(mediaBox.x1,0)?0:-mediaBox.x1; |
|
|
double shiftY = Utils::doubleEquals(mediaBox.y1,0)?0:-mediaBox.y1; |
|
|
Translation compensation(shiftX,shiftY); |
|
|
description.basePageTransformation.addAnnotsTransformation(compensation); |
|
|
} |
|
|
} |
|
|
} |
|
|
processBasePageResources(sourcePage->_root); |
|
|
sourcePageToXObject = sourcePage->pageToXObject(toAllObjects, annotations, isPageDuplicated); |
|
|
Rectangle mediaBox("/BBox", sourcePageToXObject->getObjectContent()); |
|
|
description.basePageTransformation.recalculateTranslation(mediaBox.getWidth(),mediaBox.getHeight()); |
|
|
} |
|
|
|
|
|
Object * catalog = 0; |
|
|
unsigned int fake; |
|
|
if(!parentDocument->getDocumentObject()->findObject(std::string("/Kids"), catalog, fake)) |
|
|
{ |
|
|
std::string error("Wrong document "); |
|
|
error.append("There is no object with Kids field"); |
|
|
throw Exception(error); |
|
|
} |
|
|
Object::ReferencePositionsInContent pagePosition = catalog->removeChild(_root); |
|
|
//create merged Page |
|
|
unsigned int contentPosition, parentPosition, originalPage1Position, originalPage2Position; |
|
|
std::pair<unsigned int, unsigned int> originalPageNumbers(_root->getObjectNumber(), 0); |
|
|
if(!description.skipBasePage) |
|
|
originalPageNumbers.second = sourcePageToXObject->getObjectNumber(); |
|
|
std::vector <Object::ChildAndItPositionInContent> annotsAndItPositions; |
|
|
std::string mergedPageContent = _getMergedPageContent(contentPosition, |
|
|
parentPosition, |
|
|
originalPage1Position, |
|
|
originalPage2Position, |
|
|
originalPageNumbers, |
|
|
description, |
|
|
sourcePageToXObject, |
|
|
annotations, |
|
|
annotsAndItPositions |
|
|
); |
|
|
Object * mergedPage = new Object(_root->getObjectNumber(), _root->getgenerationNumber(), mergedPageContent); |
|
|
toAllObjects.push_back(mergedPage); |
|
|
std::vector < unsigned int > contentPositionVec, parentPositionVec, originalPage1PositionVec, originalPage2PositionVec; |
|
|
contentPositionVec.push_back(contentPosition); |
|
|
parentPositionVec.push_back(parentPosition); |
|
|
originalPage1PositionVec.push_back(originalPage1Position); |
|
|
originalPage2PositionVec.push_back(originalPage2Position); |
|
|
Object * contentOfMergedPage = new Object(1, 0, _getContentOfContentObject(description)); |
|
|
toAllObjects.push_back(contentOfMergedPage); |
|
|
parentDocument->addToAllObjects(toAllObjects); |
|
|
mergedPage->addChild(contentOfMergedPage, contentPositionVec); |
|
|
mergedPage->addChild(catalog, parentPositionVec); |
|
|
if(!description.skipOverlayPage) |
|
|
mergedPage->addChild(_root, originalPage1PositionVec); |
|
|
if(!description.skipBasePage) |
|
|
mergedPage->addChild(sourcePageToXObject, originalPage2PositionVec); |
|
|
// Annotation parent page should be changed, since we moved old page |
|
|
// to Xobject |
|
|
if( !description.skipBasePage ) |
|
|
{ |
|
|
for(size_t i = 0; i< annotations.size();i++) |
|
|
{ |
|
|
_updateAnnotParentPage(annotations[i],mergedPage); |
|
|
} |
|
|
} |
|
|
for(size_t i = 0; i < annotsAndItPositions.size(); ++i) |
|
|
{ |
|
|
mergedPage->addChild(annotsAndItPositions[i].first, annotsAndItPositions[i].second); |
|
|
} |
|
|
catalog->addChild(mergedPage, pagePosition); |
|
|
_root = mergedPage; |
|
|
} |
|
|
|
|
|
|
|
|
|