"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.

    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