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 "../../../include/fpdfapi/fpdf_page.h"
      8 #include "../../../include/fpdfapi/fpdf_serial.h"
      9 #include "../../../include/fpdfapi/fpdf_module.h"
     10 #include "../../../include/fxcodec/fx_codec.h"
     11 #include "../fpdf_page/pageint.h"
     12 CFX_ByteTextBuf& operator << (CFX_ByteTextBuf& ar, CFX_AffineMatrix& matrix)
     13 {
     14     ar << matrix.a << " " << matrix.b << " " << matrix.c << " " << matrix.d << " " << matrix.e << " " << matrix.f;
     15     return ar;
     16 }
     17 CPDF_PageContentGenerate::CPDF_PageContentGenerate(CPDF_Page* pPage) : m_pPage(pPage)
     18 {
     19     m_pDocument = NULL;
     20     if (m_pPage) {
     21         m_pDocument = m_pPage->m_pDocument;
     22     }
     23 }
     24 CPDF_PageContentGenerate::~CPDF_PageContentGenerate()
     25 {
     26     for (int i = 0; i < m_pageObjects.GetSize(); ++i) {
     27         CPDF_PageObject* pPageObj = (CPDF_PageObject*)m_pageObjects[i];
     28         if (pPageObj) {
     29             pPageObj->Release();
     30         }
     31     }
     32 }
     33 FX_BOOL CPDF_PageContentGenerate::InsertPageObject(CPDF_PageObject* pPageObject)
     34 {
     35     if (!pPageObject) {
     36         return FALSE;
     37     }
     38     return m_pageObjects.Add(pPageObject);
     39 }
     40 void CPDF_PageContentGenerate::GenerateContent()
     41 {
     42     CFX_ByteTextBuf buf;
     43     CPDF_Dictionary* pPageDict = m_pPage->m_pFormDict;
     44     for (int i = 0; i < m_pageObjects.GetSize(); ++i) {
     45         CPDF_PageObject* pPageObj = (CPDF_PageObject*)m_pageObjects[i];
     46         if (!pPageObj || pPageObj->m_Type != PDFPAGE_IMAGE) {
     47             continue;
     48         }
     49         ProcessImage(buf, (CPDF_ImageObject*)pPageObj);
     50     }
     51     CPDF_Object* pContent = pPageDict->GetElementValue("Contents");
     52     if (pContent != NULL) {
     53         pPageDict->RemoveAt("Contents");
     54     }
     55     CPDF_Stream* pStream = FX_NEW CPDF_Stream(NULL, 0, NULL);
     56     pStream->SetData(buf.GetBuffer(), buf.GetLength(), FALSE, FALSE);
     57     m_pDocument->AddIndirectObject(pStream);
     58     pPageDict->SetAtReference("Contents", m_pDocument, pStream->GetObjNum());
     59 }
     60 CFX_ByteString CPDF_PageContentGenerate::RealizeResource(CPDF_Object* pResourceObj, const FX_CHAR* szType)
     61 {
     62     if (m_pPage->m_pResources == NULL) {
     63         m_pPage->m_pResources = FX_NEW CPDF_Dictionary;
     64         int objnum = m_pDocument->AddIndirectObject(m_pPage->m_pResources);
     65         m_pPage->m_pFormDict->SetAtReference("Resources", m_pDocument, objnum);
     66     }
     67     CPDF_Dictionary* pResList = m_pPage->m_pResources->GetDict(szType);
     68     if (pResList == NULL) {
     69         pResList = FX_NEW CPDF_Dictionary;
     70         m_pPage->m_pResources->SetAt(szType, pResList);
     71     }
     72     m_pDocument->AddIndirectObject(pResourceObj);
     73     CFX_ByteString name;
     74     int idnum = 1;
     75     while (1) {
     76         name.Format("FX%c%d", szType[0], idnum);
     77         if (!pResList->KeyExist(name)) {
     78             break;
     79         }
     80         idnum ++;
     81     }
     82     pResList->AddReference(name, m_pDocument, pResourceObj->GetObjNum());
     83     return name;
     84 }
     85 void CPDF_PageContentGenerate::ProcessImage(CFX_ByteTextBuf& buf, CPDF_ImageObject* pImageObj)
     86 {
     87     if ((pImageObj->m_Matrix.a == 0 && pImageObj->m_Matrix.b == 0) ||
     88             (pImageObj->m_Matrix.c == 0 && pImageObj->m_Matrix.d == 0)) {
     89         return;
     90     }
     91     buf << "q " << pImageObj->m_Matrix << " cm ";
     92     if (!pImageObj->m_pImage->IsInline()) {
     93         CPDF_Stream* pStream = pImageObj->m_pImage->GetStream();
     94         FX_DWORD dwSavedObjNum = pStream->GetObjNum();
     95         CFX_ByteString name = RealizeResource(pStream, "XObject");
     96         if (dwSavedObjNum == 0) {
     97             pImageObj->m_pImage->Release();
     98             pImageObj->m_pImage = m_pDocument->GetPageData()->GetImage(pStream);
     99         }
    100         buf << "/" << PDF_NameEncode(name) << " Do Q\n";
    101     }
    102 }
    103 void CPDF_PageContentGenerate::ProcessForm(CFX_ByteTextBuf& buf, FX_LPCBYTE data, FX_DWORD size, CFX_Matrix& matrix)
    104 {
    105     if (!data || !size) {
    106         return;
    107     }
    108     CPDF_Stream* pStream = FX_NEW CPDF_Stream(NULL, 0, NULL);
    109     CPDF_Dictionary* pFormDict = CPDF_Dictionary::Create();
    110     pFormDict->SetAtName(FX_BSTR("Type"), FX_BSTR("XObject"));
    111     pFormDict->SetAtName(FX_BSTR("Subtype"), FX_BSTR("Form"));
    112     CFX_FloatRect bbox = m_pPage->GetPageBBox();
    113     matrix.TransformRect(bbox);
    114     pFormDict->SetAtRect(FX_BSTR("BBox"), bbox);
    115     pStream->InitStream((FX_LPBYTE)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 {
    122     CPDF_Object* pContent = m_pPage->m_pFormDict->GetElementValue("Contents");
    123     if (!pContent) {
    124         return;
    125     }
    126     CFX_ByteTextBuf buf;
    127     int type = pContent->GetType();
    128     if (type == PDFOBJ_ARRAY) {
    129         CPDF_Array* pArray = (CPDF_Array*)pContent;
    130         int iCount = pArray->GetCount();
    131         CPDF_StreamAcc** pContentArray = (CPDF_StreamAcc**)FX_Alloc(CPDF_StreamAcc*, iCount);
    132         int size = 0;
    133         int i = 0;
    134         for (i = 0; i < iCount; ++i) {
    135             pContent = pArray->GetElement(i);
    136             if (!pContent || pContent->GetType() != PDFOBJ_STREAM) {
    137                 continue;
    138             }
    139             CPDF_StreamAcc* pStream = FX_NEW CPDF_StreamAcc();
    140             pStream->LoadAllData((CPDF_Stream*)pContent);
    141             pContentArray[i] = pStream;
    142             size += pContentArray[i]->GetSize() + 1;
    143         }
    144         int pos = 0;
    145         FX_LPBYTE pBuf = FX_Alloc(FX_BYTE, size);
    146         for (i = 0; i < iCount; ++i) {
    147             FXSYS_memcpy32(pBuf + pos, pContentArray[i]->GetData(), 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 (type == PDFOBJ_STREAM) {
    156         CPDF_StreamAcc contentStream;
    157         contentStream.LoadAllData((CPDF_Stream*)pContent);
    158         ProcessForm(buf, contentStream.GetData(), contentStream.GetSize(), matrix);
    159     }
    160     CPDF_Stream* pStream = FX_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, pStream->GetObjNum());
    164 }
    165