"Fossies" - the Fresh Open Source Software Archive

Member "xpdf-4.04/xpdf/Page.cc" (18 Apr 2022, 13874 Bytes) of package /linux/misc/xpdf-4.04.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Page.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.03_vs_4.04.

    1 //========================================================================
    2 //
    3 // Page.cc
    4 //
    5 // Copyright 1996-2007 Glyph & Cog, LLC
    6 //
    7 //========================================================================
    8 
    9 #include <aconf.h>
   10 
   11 #ifdef USE_GCC_PRAGMAS
   12 #pragma implementation
   13 #endif
   14 
   15 #include <stddef.h>
   16 #include "gmempp.h"
   17 #include "Trace.h"
   18 #include "GlobalParams.h"
   19 #include "Object.h"
   20 #include "Array.h"
   21 #include "Dict.h"
   22 #include "PDFDoc.h"
   23 #include "XRef.h"
   24 #include "Link.h"
   25 #include "OutputDev.h"
   26 #ifndef PDF_PARSER_ONLY
   27 #include "Gfx.h"
   28 #include "GfxState.h"
   29 #include "Annot.h"
   30 #include "AcroForm.h"
   31 #endif
   32 #include "Error.h"
   33 #include "Catalog.h"
   34 #include "Page.h"
   35 
   36 //------------------------------------------------------------------------
   37 // PDFRectangle
   38 //------------------------------------------------------------------------
   39 
   40 void PDFRectangle::clipTo(PDFRectangle *rect) {
   41   if (x1 < rect->x1) {
   42     x1 = rect->x1;
   43   } else if (x1 > rect->x2) {
   44     x1 = rect->x2;
   45   }
   46   if (x2 < rect->x1) {
   47     x2 = rect->x1;
   48   } else if (x2 > rect->x2) {
   49     x2 = rect->x2;
   50   }
   51   if (y1 < rect->y1) {
   52     y1 = rect->y1;
   53   } else if (y1 > rect->y2) {
   54     y1 = rect->y2;
   55   }
   56   if (y2 < rect->y1) {
   57     y2 = rect->y1;
   58   } else if (y2 > rect->y2) {
   59     y2 = rect->y2;
   60   }
   61 }
   62 
   63 //------------------------------------------------------------------------
   64 // PageAttrs
   65 //------------------------------------------------------------------------
   66 
   67 PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict, XRef *xref) {
   68   Object obj1;
   69 
   70   // get old/default values
   71   if (attrs) {
   72     mediaBox = attrs->mediaBox;
   73     cropBox = attrs->cropBox;
   74     haveCropBox = attrs->haveCropBox;
   75     rotate = attrs->rotate;
   76   } else {
   77     // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
   78     // but some (non-compliant) PDF files don't specify a MediaBox
   79     mediaBox.x1 = 0;
   80     mediaBox.y1 = 0;
   81     mediaBox.x2 = 612;
   82     mediaBox.y2 = 792;
   83     cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
   84     haveCropBox = gFalse;
   85     rotate = 0;
   86   }
   87 
   88   // media box
   89   readBox(dict, "MediaBox", &mediaBox);
   90 
   91   // crop box
   92   if (readBox(dict, "CropBox", &cropBox)) {
   93     haveCropBox = gTrue;
   94   }
   95   if (!haveCropBox) {
   96     cropBox = mediaBox;
   97   }
   98 
   99   // other boxes
  100   bleedBox = cropBox;
  101   readBox(dict, "BleedBox", &bleedBox);
  102   trimBox = cropBox;
  103   readBox(dict, "TrimBox", &trimBox);
  104   artBox = cropBox;
  105   readBox(dict, "ArtBox", &artBox);
  106 
  107   // rotate
  108   dict->lookup("Rotate", &obj1);
  109   if (obj1.isInt()) {
  110     rotate = obj1.getInt();
  111   }
  112   obj1.free();
  113   while (rotate < 0) {
  114     rotate += 360;
  115   }
  116   while (rotate >= 360) {
  117     rotate -= 360;
  118   }
  119 
  120   // misc attributes
  121   dict->lookup("LastModified", &lastModified);
  122   dict->lookup("BoxColorInfo", &boxColorInfo);
  123   dict->lookup("Group", &group);
  124   dict->lookup("Metadata", &metadata);
  125   dict->lookup("PieceInfo", &pieceInfo);
  126   dict->lookup("SeparationInfo", &separationInfo);
  127   if (dict->lookup("UserUnit", &obj1)->isNum()) {
  128     userUnit = obj1.getNum();
  129     if (userUnit < 1) {
  130       userUnit = 1;
  131     }
  132   } else {
  133     userUnit = 1;
  134   }
  135   obj1.free();
  136 
  137   // resource dictionary
  138   Object childResDictObj;
  139   dict->lookup("Resources", &childResDictObj);
  140   if (attrs && attrs->resources.isDict() && childResDictObj.isDict()) {
  141     // merge this node's resources into the parent's resources
  142     // (some PDF files violate the PDF spec and expect this merging)
  143     resources.initDict(xref);
  144     Dict *resDict = resources.getDict();
  145     Dict *parentResDict = attrs->resources.getDict();
  146     for (int i = 0; i < parentResDict->getLength(); ++i) {
  147       char *resType = parentResDict->getKey(i);
  148       Object subdictObj1;
  149       if (parentResDict->getVal(i, &subdictObj1)->isDict()) {
  150     Dict *subdict1 = subdictObj1.getDict();
  151     Object subdictObj2;
  152     subdictObj2.initDict(xref);
  153     Dict *subdict2 = subdictObj2.getDict();
  154     for (int j = 0; j < subdict1->getLength(); ++j) {
  155       subdict1->getValNF(j, &obj1);
  156       subdict2->add(copyString(subdict1->getKey(j)), &obj1);
  157     }
  158     resDict->add(copyString(resType), &subdictObj2);
  159       }
  160       subdictObj1.free();
  161     }
  162     Dict *childResDict = childResDictObj.getDict();
  163     for (int i = 0; i < childResDict->getLength(); ++i) {
  164       char *resType = childResDict->getKey(i);
  165       Object subdictObj1;
  166       if (childResDict->getVal(i, &subdictObj1)->isDict()) {
  167     Object subdictObj2;
  168     if (resDict->lookup(resType, &subdictObj2)->isDict()) {
  169       Dict *subdict1 = subdictObj1.getDict();
  170       Dict *subdict2 = subdictObj2.getDict();
  171       for (int j = 0; j < subdict1->getLength(); ++j) {
  172         subdict1->getValNF(j, &obj1);
  173         subdict2->add(copyString(subdict1->getKey(j)), &obj1);
  174       }
  175       subdictObj2.free();
  176     } else {
  177       subdictObj2.free();
  178       resDict->add(copyString(resType), subdictObj1.copy(&subdictObj2));
  179     }
  180       }
  181       subdictObj1.free();
  182     }
  183   } else if (attrs && attrs->resources.isDict()) {
  184     attrs->resources.copy(&resources);
  185   } else if (childResDictObj.isDict()) {
  186     childResDictObj.copy(&resources);
  187   } else {
  188     resources.initNull();
  189   }
  190   childResDictObj.free();
  191 }
  192 
  193 PageAttrs::PageAttrs() {
  194   mediaBox.x1 = mediaBox.y1 = 0;
  195   mediaBox.x2 = mediaBox.y2 = 50;
  196   cropBox = mediaBox;
  197   haveCropBox = gFalse;
  198   bleedBox = cropBox;
  199   trimBox = cropBox;
  200   artBox = cropBox;
  201   rotate = 0;
  202   lastModified.initNull();
  203   boxColorInfo.initNull();
  204   group.initNull();
  205   metadata.initNull();
  206   pieceInfo.initNull();
  207   separationInfo.initNull();
  208   userUnit = 1;
  209   resources.initNull();
  210 }
  211 
  212 PageAttrs::~PageAttrs() {
  213   lastModified.free();
  214   boxColorInfo.free();
  215   group.free();
  216   metadata.free();
  217   pieceInfo.free();
  218   separationInfo.free();
  219   resources.free();
  220 }
  221 
  222 void PageAttrs::clipBoxes() {
  223   cropBox.clipTo(&mediaBox);
  224   bleedBox.clipTo(&mediaBox);
  225   trimBox.clipTo(&mediaBox);
  226   artBox.clipTo(&mediaBox);
  227 }
  228 
  229 GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) {
  230   PDFRectangle tmp;
  231   double t;
  232   Object obj1, obj2;
  233   GBool ok;
  234 
  235   dict->lookup(key, &obj1);
  236   if (obj1.isArray() && obj1.arrayGetLength() == 4) {
  237     ok = gTrue;
  238     obj1.arrayGet(0, &obj2);
  239     if (obj2.isNum()) {
  240       tmp.x1 = obj2.getNum();
  241     } else {
  242       ok = gFalse;
  243     }
  244     obj2.free();
  245     obj1.arrayGet(1, &obj2);
  246     if (obj2.isNum()) {
  247       tmp.y1 = obj2.getNum();
  248     } else {
  249       ok = gFalse;
  250     }
  251     obj2.free();
  252     obj1.arrayGet(2, &obj2);
  253     if (obj2.isNum()) {
  254       tmp.x2 = obj2.getNum();
  255     } else {
  256       ok = gFalse;
  257     }
  258     obj2.free();
  259     obj1.arrayGet(3, &obj2);
  260     if (obj2.isNum()) {
  261       tmp.y2 = obj2.getNum();
  262     } else {
  263       ok = gFalse;
  264     }
  265     obj2.free();
  266     if (ok) {
  267       if (tmp.x1 > tmp.x2) {
  268     t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t;
  269       }
  270       if (tmp.y1 > tmp.y2) {
  271     t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t;
  272       }
  273       *box = tmp;
  274     }
  275   } else {
  276     ok = gFalse;
  277   }
  278   obj1.free();
  279   return ok;
  280 }
  281 
  282 //------------------------------------------------------------------------
  283 // Page
  284 //------------------------------------------------------------------------
  285 
  286 Page::Page(PDFDoc *docA, int numA, Dict *pageDict, PageAttrs *attrsA) {
  287   ok = gTrue;
  288   doc = docA;
  289   xref = doc->getXRef();
  290   num = numA;
  291 
  292   // get attributes
  293   attrs = attrsA;
  294   attrs->clipBoxes();
  295 
  296   // annotations
  297   pageDict->lookupNF("Annots", &annots);
  298   if (!(annots.isRef() || annots.isArray() || annots.isNull())) {
  299     error(errSyntaxError, -1,
  300       "Page annotations object (page {0:d}) is wrong type ({1:s})",
  301       num, annots.getTypeName());
  302     annots.free();
  303     goto err2;
  304   }
  305 
  306   // contents
  307   pageDict->lookupNF("Contents", &contents);
  308   if (!(contents.isRef() || contents.isArray() ||
  309     contents.isNull())) {
  310     error(errSyntaxError, -1,
  311       "Page contents object (page {0:d}) is wrong type ({1:s})",
  312       num, contents.getTypeName());
  313     contents.free();
  314     goto err1;
  315   }
  316 
  317   // thumbnail
  318   pageDict->lookupNF("Thumb", &thumbnail);
  319   if (!thumbnail.isRef()) {
  320     if (!thumbnail.isNull()) {
  321       thumbnail.free();
  322       thumbnail.initNull();
  323     }
  324   }
  325 
  326   return;
  327 
  328  err2:
  329   annots.initNull();
  330  err1:
  331   contents.initNull();
  332   thumbnail.initNull();
  333   ok = gFalse;
  334 }
  335 
  336 Page::Page(PDFDoc *docA, int numA) {
  337   doc = docA;
  338   xref = doc->getXRef();
  339   num = numA;
  340   attrs = new PageAttrs();
  341   annots.initNull();
  342   contents.initNull();
  343   thumbnail.initNull();
  344   ok = gTrue;
  345 }
  346 
  347 Page::~Page() {
  348   delete attrs;
  349   annots.free();
  350   contents.free();
  351   thumbnail.free();
  352 }
  353 
  354 Links *Page::getLinks() {
  355   Links *links;
  356   Object obj;
  357 
  358   links = new Links(getAnnots(&obj), doc->getCatalog()->getBaseURI());
  359   obj.free();
  360   return links;
  361 }
  362 
  363 void Page::display(OutputDev *out, double hDPI, double vDPI,
  364            int rotate, GBool useMediaBox, GBool crop,
  365            GBool printing,
  366            GBool (*abortCheckCbk)(void *data),
  367            void *abortCheckCbkData) {
  368   displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
  369            -1, -1, -1, -1, printing,
  370            abortCheckCbk, abortCheckCbkData);
  371 }
  372 
  373 void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
  374             int rotate, GBool useMediaBox, GBool crop,
  375             int sliceX, int sliceY, int sliceW, int sliceH,
  376             GBool printing,
  377             GBool (*abortCheckCbk)(void *data),
  378             void *abortCheckCbkData) {
  379 #ifndef PDF_PARSER_ONLY
  380   PDFRectangle *mediaBox, *cropBox;
  381   PDFRectangle box;
  382   Gfx *gfx;
  383   Object obj;
  384   Annots *annotList;
  385   AcroForm *form;
  386   int i;
  387 
  388   if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop,
  389                sliceX, sliceY, sliceW, sliceH,
  390                printing, abortCheckCbk, abortCheckCbkData)) {
  391     return;
  392   }
  393 
  394   traceBegin(this, "begin page");
  395 
  396   rotate += getRotate();
  397   if (rotate >= 360) {
  398     rotate -= 360;
  399   } else if (rotate < 0) {
  400     rotate += 360;
  401   }
  402 
  403   makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(),
  404       sliceX, sliceY, sliceW, sliceH, &box, &crop);
  405   cropBox = getCropBox();
  406 
  407   if (globalParams->getPrintCommands()) {
  408     mediaBox = getMediaBox();
  409     printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
  410        mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2);
  411     printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
  412        cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
  413     printf("***** Rotate = %d\n", attrs->getRotate());
  414   }
  415 
  416   gfx = new Gfx(doc, out, num, attrs->getResourceDict(),
  417         hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL,
  418         rotate, abortCheckCbk, abortCheckCbkData);
  419   contents.fetch(xref, &obj);
  420   if (!obj.isNull()) {
  421     gfx->saveState();
  422     gfx->display(&contents);
  423     gfx->endOfPage();
  424   }
  425   obj.free();
  426 
  427   // draw (non-form) annotations
  428   if (globalParams->getDrawAnnotations()) {
  429     annotList = new Annots(doc, getAnnots(&obj));
  430     obj.free();
  431     annotList->generateAnnotAppearances();
  432     if (annotList->getNumAnnots() > 0) {
  433       if (globalParams->getPrintCommands()) {
  434     printf("***** Annotations\n");
  435       }
  436       for (i = 0; i < annotList->getNumAnnots(); ++i) {
  437     if (abortCheckCbk && (*abortCheckCbk)(abortCheckCbkData)) {
  438       break;
  439     }
  440     annotList->getAnnot(i)->draw(gfx, printing);
  441       }
  442     }
  443     delete annotList;
  444   }
  445 
  446   // draw form fields
  447   if (globalParams->getDrawFormFields()) {
  448     if ((form = doc->getCatalog()->getForm())) {
  449       if (!(abortCheckCbk && (*abortCheckCbk)(abortCheckCbkData))) {
  450     form->draw(num, gfx, printing);
  451       }
  452     }
  453   }
  454 
  455   delete gfx;
  456 #endif // PDF_PARSER_ONLY
  457 
  458   traceEnd(this, "end page");
  459 }
  460 
  461 void Page::makeBox(double hDPI, double vDPI, int rotate,
  462            GBool useMediaBox, GBool upsideDown,
  463            double sliceX, double sliceY, double sliceW, double sliceH,
  464            PDFRectangle *box, GBool *crop) {
  465   PDFRectangle *mediaBox, *cropBox, *baseBox;
  466   double kx, ky;
  467 
  468   mediaBox = getMediaBox();
  469   cropBox = getCropBox();
  470   if (sliceW >= 0 && sliceH >= 0) {
  471     baseBox = useMediaBox ? mediaBox : cropBox;
  472     kx = 72.0 / hDPI;
  473     ky = 72.0 / vDPI;
  474     if (rotate == 90) {
  475       if (upsideDown) {
  476     box->x1 = baseBox->x1 + ky * sliceY;
  477     box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
  478       } else {
  479     box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
  480     box->x2 = baseBox->x2 - ky * sliceY;
  481       }
  482       box->y1 = baseBox->y1 + kx * sliceX;
  483       box->y2 = baseBox->y1 + kx * (sliceX + sliceW);
  484     } else if (rotate == 180) {
  485       box->x1 = baseBox->x2 - kx * (sliceX + sliceW);
  486       box->x2 = baseBox->x2 - kx * sliceX;
  487       if (upsideDown) {
  488     box->y1 = baseBox->y1 + ky * sliceY;
  489     box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
  490       } else {
  491     box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
  492     box->y2 = baseBox->y2 - ky * sliceY;
  493       }
  494     } else if (rotate == 270) {
  495       if (upsideDown) {
  496     box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
  497     box->x2 = baseBox->x2 - ky * sliceY;
  498       } else {
  499     box->x1 = baseBox->x1 + ky * sliceY;
  500     box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
  501       }
  502       box->y1 = baseBox->y2 - kx * (sliceX + sliceW);
  503       box->y2 = baseBox->y2 - kx * sliceX;
  504     } else {
  505       box->x1 = baseBox->x1 + kx * sliceX;
  506       box->x2 = baseBox->x1 + kx * (sliceX + sliceW);
  507       if (upsideDown) {
  508     box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
  509     box->y2 = baseBox->y2 - ky * sliceY;
  510       } else {
  511     box->y1 = baseBox->y1 + ky * sliceY;
  512     box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
  513       }
  514     }
  515   } else if (useMediaBox) {
  516     *box = *mediaBox;
  517   } else {
  518     *box = *cropBox;
  519     *crop = gFalse;
  520   }
  521 }
  522 
  523 void Page::processLinks(OutputDev *out) {
  524   Links *links;
  525   int i;
  526 
  527   links = getLinks();
  528   for (i = 0; i < links->getNumLinks(); ++i) {
  529     out->processLink(links->getLink(i));
  530   }
  531   delete links;
  532 }
  533 
  534 #ifndef PDF_PARSER_ONLY
  535 void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
  536              int rotate, GBool useMediaBox, GBool upsideDown) {
  537   GfxState *state;
  538   int i;
  539 
  540   rotate += getRotate();
  541   if (rotate >= 360) {
  542     rotate -= 360;
  543   } else if (rotate < 0) {
  544     rotate += 360;
  545   }
  546   state = new GfxState(hDPI, vDPI,
  547                useMediaBox ? getMediaBox() : getCropBox(),
  548                rotate, upsideDown);
  549   for (i = 0; i < 6; ++i) {
  550     ctm[i] = state->getCTM()[i];
  551   }
  552   delete state;
  553 }
  554 #endif