Home | History | Annotate | Download | only in fpdf_edit
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/include/fpdfapi/fpdf_module.h"
      8 #include "core/include/fpdfapi/fpdf_page.h"
      9 #include "core/include/fpdfapi/fpdf_serial.h"
     10 #include "core/src/fpdfapi/fpdf_page/pageint.h"
     11 
     12 CFX_ByteTextBuf& operator<<(CFX_ByteTextBuf& ar, CFX_Matrix& matrix) {
     13   ar << matrix.a << " " << matrix.b << " " << matrix.c << " " << matrix.d << " "
     14      << matrix.e << " " << matrix.f;
     15   return ar;
     16 }
     17 CPDF_PageContentGenerate::CPDF_PageContentGenerate(CPDF_Page* pPage)
     18     : m_pPage(pPage) {
     19   m_pDocument = NULL;
     20   if (m_pPage) {
     21     m_pDocument = m_pPage->m_pDocument;
     22   }
     23   FX_POSITION pos = pPage->GetFirstObjectPosition();
     24   while (pos) {
     25     InsertPageObject(pPage->GetNextObject(pos));
     26   }
     27 }
     28 CPDF_PageContentGenerate::~CPDF_PageContentGenerate() {}
     29 FX_BOOL CPDF_PageContentGenerate::InsertPageObject(
     30     CPDF_PageObject* pPageObject) {
     31   if (!pPageObject) {
     32     return FALSE;
     33   }
     34   return m_pageObjects.Add(pPageObject);
     35 }
     36 void CPDF_PageContentGenerate::GenerateContent() {
     37   CFX_ByteTextBuf buf;
     38   CPDF_Dictionary* pPageDict = m_pPage->m_pFormDict;
     39   for (int i = 0; i < m_pageObjects.GetSize(); ++i) {
     40     CPDF_PageObject* pPageObj = m_pageObjects[i];
     41     if (!pPageObj || pPageObj->m_Type != PDFPAGE_IMAGE) {
     42       continue;
     43     }
     44     ProcessImage(buf, (CPDF_ImageObject*)pPageObj);
     45   }
     46   CPDF_Object* pContent =
     47       pPageDict ? pPageDict->GetElementValue("Contents") : NULL;
     48   if (pContent) {
     49     pPageDict->RemoveAt("Contents");
     50   }
     51   CPDF_Stream* pStream = new CPDF_Stream(NULL, 0, NULL);
     52   pStream->SetData(buf.GetBuffer(), buf.GetLength(), FALSE, FALSE);
     53   m_pDocument->AddIndirectObject(pStream);
     54   pPageDict->SetAtReference("Contents", m_pDocument, pStream->GetObjNum());
     55 }
     56 CFX_ByteString CPDF_PageContentGenerate::RealizeResource(
     57     CPDF_Object* pResourceObj,
     58     const FX_CHAR* szType) {
     59   if (!m_pPage->m_pResources) {
     60     m_pPage->m_pResources = new CPDF_Dictionary;
     61     int objnum = m_pDocument->AddIndirectObject(m_pPage->m_pResources);
     62     m_pPage->m_pFormDict->SetAtReference("Resources", m_pDocument, objnum);
     63   }
     64   CPDF_Dictionary* pResList = m_pPage->m_pResources->GetDict(szType);
     65   if (!pResList) {
     66     pResList = new CPDF_Dictionary;
     67     m_pPage->m_pResources->SetAt(szType, pResList);
     68   }
     69   m_pDocument->AddIndirectObject(pResourceObj);
     70   CFX_ByteString name;
     71   int idnum = 1;
     72   while (1) {
     73     name.Format("FX%c%d", szType[0], idnum);
     74     if (!pResList->KeyExist(name)) {
     75       break;
     76     }
     77     idnum++;
     78   }
     79   pResList->AddReference(name, m_pDocument, pResourceObj->GetObjNum());
     80   return name;
     81 }
     82 void CPDF_PageContentGenerate::ProcessImage(CFX_ByteTextBuf& buf,
     83                                             CPDF_ImageObject* pImageObj) {
     84   if ((pImageObj->m_Matrix.a == 0 && pImageObj->m_Matrix.b == 0) ||
     85       (pImageObj->m_Matrix.c == 0 && pImageObj->m_Matrix.d == 0)) {
     86     return;
     87   }
     88   buf << "q " << pImageObj->m_Matrix << " cm ";
     89   if (!pImageObj->m_pImage->IsInline()) {
     90     CPDF_Stream* pStream = pImageObj->m_pImage->GetStream();
     91     FX_DWORD dwSavedObjNum = pStream->GetObjNum();
     92     CFX_ByteString name = RealizeResource(pStream, "XObject");
     93     if (dwSavedObjNum == 0) {
     94       if (pImageObj->m_pImage)
     95         pImageObj->m_pImage->Release();
     96       pImageObj->m_pImage = m_pDocument->GetPageData()->GetImage(pStream);
     97     }
     98     buf << "/" << PDF_NameEncode(name) << " Do Q\n";
     99   }
    100 }
    101 void CPDF_PageContentGenerate::ProcessForm(CFX_ByteTextBuf& buf,
    102                                            const uint8_t* data,
    103                                            FX_DWORD size,
    104                                            CFX_Matrix& matrix) {
    105   if (!data || !size) {
    106     return;
    107   }
    108   CPDF_Stream* pStream = new CPDF_Stream(NULL, 0, NULL);
    109   CPDF_Dictionary* pFormDict = new CPDF_Dictionary;
    110   pFormDict->SetAtName("Type", "XObject");
    111   pFormDict->SetAtName("Subtype", "Form");
    112   CFX_FloatRect bbox = m_pPage->GetPageBBox();
    113   matrix.TransformRect(bbox);
    114   pFormDict->SetAtRect("BBox", bbox);
    115   pStream->InitStream((uint8_t*)data, size, pFormDict);
    116   buf << "q " << matrix << " cm ";
    117   CFX_ByteString name = RealizeResource(pStream, "XObject");
    118   buf << "/" << PDF_NameEncode(name) << " Do Q\n";
    119 }
    120 void CPDF_PageContentGenerate::TransformContent(CFX_Matrix& matrix) {
    121   CPDF_Dictionary* pDict = m_pPage->m_pFormDict;
    122   CPDF_Object* pContent = pDict ? pDict->GetElementValue("Contents") : NULL;
    123   if (!pContent)
    124     return;
    125 
    126   CFX_ByteTextBuf buf;
    127   if (CPDF_Array* pArray = pContent->AsArray()) {
    128     int iCount = pArray->GetCount();
    129     CPDF_StreamAcc** pContentArray = FX_Alloc(CPDF_StreamAcc*, iCount);
    130     int size = 0;
    131     int i = 0;
    132     for (i = 0; i < iCount; ++i) {
    133       pContent = pArray->GetElement(i);
    134       CPDF_Stream* pStream = ToStream(pContent);
    135       if (!pStream)
    136         continue;
    137 
    138       CPDF_StreamAcc* pStreamAcc = new CPDF_StreamAcc();
    139       pStreamAcc->LoadAllData(pStream);
    140       pContentArray[i] = pStreamAcc;
    141       size += pContentArray[i]->GetSize() + 1;
    142     }
    143     int pos = 0;
    144     uint8_t* pBuf = FX_Alloc(uint8_t, size);
    145     for (i = 0; i < iCount; ++i) {
    146       FXSYS_memcpy(pBuf + pos, pContentArray[i]->GetData(),
    147                    pContentArray[i]->GetSize());
    148       pos += pContentArray[i]->GetSize() + 1;
    149       pBuf[pos - 1] = ' ';
    150       delete pContentArray[i];
    151     }
    152     ProcessForm(buf, pBuf, size, matrix);
    153     FX_Free(pBuf);
    154     FX_Free(pContentArray);
    155   } else if (CPDF_Stream* pStream = pContent->AsStream()) {
    156     CPDF_StreamAcc contentStream;
    157     contentStream.LoadAllData(pStream);
    158     ProcessForm(buf, contentStream.GetData(), contentStream.GetSize(), matrix);
    159   }
    160   CPDF_Stream* pStream = new CPDF_Stream(NULL, 0, NULL);
    161   pStream->SetData(buf.GetBuffer(), buf.GetLength(), FALSE, FALSE);
    162   m_pDocument->AddIndirectObject(pStream);
    163   m_pPage->m_pFormDict->SetAtReference("Contents", m_pDocument,
    164                                        pStream->GetObjNum());
    165 }
    166