• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "public/fpdf_edit.h"
8 
9 #include "core/fpdfapi/cpdf_modulemgr.h"
10 #include "core/fpdfapi/page/cpdf_image.h"
11 #include "core/fpdfapi/page/cpdf_imageobject.h"
12 #include "core/fpdfapi/page/cpdf_page.h"
13 #include "core/fpdfapi/page/cpdf_pageobject.h"
14 #include "core/fpdfapi/parser/cpdf_array.h"
15 #include "core/fpdfapi/parser/cpdf_name.h"
16 #include "core/fpdfapi/render/cpdf_dibsource.h"
17 #include "fpdfsdk/fsdk_define.h"
18 #include "third_party/base/ptr_util.h"
19 
20 namespace {
21 
22 // These checks ensure the consistency of colorspace values across core/ and
23 // public/.
24 static_assert(PDFCS_DEVICEGRAY == FPDF_COLORSPACE_DEVICEGRAY,
25               "PDFCS_DEVICEGRAY value mismatch");
26 static_assert(PDFCS_DEVICERGB == FPDF_COLORSPACE_DEVICERGB,
27               "PDFCS_DEVICERGB value mismatch");
28 static_assert(PDFCS_DEVICECMYK == FPDF_COLORSPACE_DEVICECMYK,
29               "PDFCS_DEVICECMYK value mismatch");
30 static_assert(PDFCS_CALGRAY == FPDF_COLORSPACE_CALGRAY,
31               "PDFCS_CALGRAY value mismatch");
32 static_assert(PDFCS_CALRGB == FPDF_COLORSPACE_CALRGB,
33               "PDFCS_CALRGB value mismatch");
34 static_assert(PDFCS_LAB == FPDF_COLORSPACE_LAB, "PDFCS_LAB value mismatch");
35 static_assert(PDFCS_ICCBASED == FPDF_COLORSPACE_ICCBASED,
36               "PDFCS_ICCBASED value mismatch");
37 static_assert(PDFCS_SEPARATION == FPDF_COLORSPACE_SEPARATION,
38               "PDFCS_SEPARATION value mismatch");
39 static_assert(PDFCS_DEVICEN == FPDF_COLORSPACE_DEVICEN,
40               "PDFCS_DEVICEN value mismatch");
41 static_assert(PDFCS_INDEXED == FPDF_COLORSPACE_INDEXED,
42               "PDFCS_INDEXED value mismatch");
43 static_assert(PDFCS_PATTERN == FPDF_COLORSPACE_PATTERN,
44               "PDFCS_PATTERN value mismatch");
45 
LoadJpegHelper(FPDF_PAGE * pages,int nCount,FPDF_PAGEOBJECT image_object,FPDF_FILEACCESS * fileAccess,bool inlineJpeg)46 bool LoadJpegHelper(FPDF_PAGE* pages,
47                     int nCount,
48                     FPDF_PAGEOBJECT image_object,
49                     FPDF_FILEACCESS* fileAccess,
50                     bool inlineJpeg) {
51   if (!image_object || !fileAccess)
52     return false;
53 
54   RetainPtr<IFX_SeekableReadStream> pFile = MakeSeekableReadStream(fileAccess);
55   CPDF_ImageObject* pImgObj = static_cast<CPDF_ImageObject*>(image_object);
56 
57   if (pages) {
58     for (int index = 0; index < nCount; index++) {
59       CPDF_Page* pPage = CPDFPageFromFPDFPage(pages[index]);
60       if (pPage)
61         pImgObj->GetImage()->ResetCache(pPage, nullptr);
62     }
63   }
64 
65   if (inlineJpeg)
66     pImgObj->GetImage()->SetJpegImageInline(pFile);
67   else
68     pImgObj->GetImage()->SetJpegImage(pFile);
69   pImgObj->SetDirty(true);
70   return true;
71 }
72 
73 }  // namespace
74 
75 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
FPDFPageObj_NewImageObj(FPDF_DOCUMENT document)76 FPDFPageObj_NewImageObj(FPDF_DOCUMENT document) {
77   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
78   if (!pDoc)
79     return nullptr;
80 
81   auto pImageObj = pdfium::MakeUnique<CPDF_ImageObject>();
82   pImageObj->SetImage(pdfium::MakeRetain<CPDF_Image>(pDoc));
83   return pImageObj.release();
84 }
85 
86 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFImageObj_LoadJpegFile(FPDF_PAGE * pages,int nCount,FPDF_PAGEOBJECT image_object,FPDF_FILEACCESS * fileAccess)87 FPDFImageObj_LoadJpegFile(FPDF_PAGE* pages,
88                           int nCount,
89                           FPDF_PAGEOBJECT image_object,
90                           FPDF_FILEACCESS* fileAccess) {
91   return LoadJpegHelper(pages, nCount, image_object, fileAccess, false);
92 }
93 
94 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFImageObj_LoadJpegFileInline(FPDF_PAGE * pages,int nCount,FPDF_PAGEOBJECT image_object,FPDF_FILEACCESS * fileAccess)95 FPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages,
96                                 int nCount,
97                                 FPDF_PAGEOBJECT image_object,
98                                 FPDF_FILEACCESS* fileAccess) {
99   return LoadJpegHelper(pages, nCount, image_object, fileAccess, true);
100 }
101 
102 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object,double a,double b,double c,double d,double e,double f)103 FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object,
104                        double a,
105                        double b,
106                        double c,
107                        double d,
108                        double e,
109                        double f) {
110   if (!image_object)
111     return false;
112 
113   CPDF_ImageObject* pImgObj = static_cast<CPDF_ImageObject*>(image_object);
114   pImgObj->set_matrix(CFX_Matrix(static_cast<float>(a), static_cast<float>(b),
115                                  static_cast<float>(c), static_cast<float>(d),
116                                  static_cast<float>(e), static_cast<float>(f)));
117   pImgObj->CalcBoundingBox();
118   pImgObj->SetDirty(true);
119   return true;
120 }
121 
122 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFImageObj_SetBitmap(FPDF_PAGE * pages,int nCount,FPDF_PAGEOBJECT image_object,FPDF_BITMAP bitmap)123 FPDFImageObj_SetBitmap(FPDF_PAGE* pages,
124                        int nCount,
125                        FPDF_PAGEOBJECT image_object,
126                        FPDF_BITMAP bitmap) {
127   if (!image_object || !bitmap || !pages)
128     return false;
129 
130   CPDF_ImageObject* pImgObj = static_cast<CPDF_ImageObject*>(image_object);
131   for (int index = 0; index < nCount; index++) {
132     CPDF_Page* pPage = CPDFPageFromFPDFPage(pages[index]);
133     if (pPage)
134       pImgObj->GetImage()->ResetCache(pPage, nullptr);
135   }
136   RetainPtr<CFX_DIBitmap> holder(CFXBitmapFromFPDFBitmap(bitmap));
137   pImgObj->GetImage()->SetImage(holder);
138   pImgObj->CalcBoundingBox();
139   pImgObj->SetDirty(true);
140   return true;
141 }
142 
143 FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV
FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object)144 FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object) {
145   CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
146   if (!pObj || !pObj->IsImage())
147     return nullptr;
148 
149   RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
150   if (!pImg)
151     return nullptr;
152 
153   RetainPtr<CFX_DIBSource> pSource = pImg->LoadDIBSource();
154   if (!pSource)
155     return nullptr;
156 
157   RetainPtr<CFX_DIBitmap> pBitmap;
158   // If the source image has a representation of 1 bit per pixel, then convert
159   // it to a grayscale bitmap having 1 byte per pixel, since bitmaps have no
160   // concept of bits. Otherwise, convert the source image to a bitmap directly,
161   // retaining its color representation.
162   if (pSource->GetBPP() == 1)
163     pBitmap = pSource->CloneConvert(FXDIB_8bppRgb);
164   else
165     pBitmap = pSource->Clone(nullptr);
166 
167   return pBitmap.Leak();
168 }
169 
170 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object,void * buffer,unsigned long buflen)171 FPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object,
172                                  void* buffer,
173                                  unsigned long buflen) {
174   CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
175   if (!pObj || !pObj->IsImage())
176     return 0;
177 
178   RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
179   if (!pImg)
180     return 0;
181 
182   CPDF_Stream* pImgStream = pImg->GetStream();
183   if (!pImgStream)
184     return 0;
185 
186   return DecodeStreamMaybeCopyAndReturnLength(pImgStream, buffer, buflen);
187 }
188 
189 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object,void * buffer,unsigned long buflen)190 FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object,
191                              void* buffer,
192                              unsigned long buflen) {
193   CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
194   if (!pObj || !pObj->IsImage())
195     return 0;
196 
197   RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
198   if (!pImg)
199     return 0;
200 
201   CPDF_Stream* pImgStream = pImg->GetStream();
202   if (!pImgStream)
203     return 0;
204 
205   uint32_t len = pImgStream->GetRawSize();
206   if (buffer && buflen >= len)
207     memcpy(buffer, pImgStream->GetRawData(), len);
208 
209   return len;
210 }
211 
212 FPDF_EXPORT int FPDF_CALLCONV
FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object)213 FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object) {
214   CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
215   if (!pObj || !pObj->IsImage())
216     return 0;
217 
218   RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
219   if (!pImg)
220     return 0;
221 
222   CPDF_Dictionary* pDict = pImg->GetDict();
223   CPDF_Object* pFilter = pDict ? pDict->GetDirectObjectFor("Filter") : nullptr;
224   if (!pFilter)
225     return 0;
226 
227   if (pFilter->IsArray())
228     return pFilter->AsArray()->GetCount();
229   if (pFilter->IsName())
230     return 1;
231 
232   return 0;
233 }
234 
235 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object,int index,void * buffer,unsigned long buflen)236 FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object,
237                             int index,
238                             void* buffer,
239                             unsigned long buflen) {
240   if (index < 0 || index >= FPDFImageObj_GetImageFilterCount(image_object))
241     return 0;
242 
243   CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
244   CPDF_Object* pFilter =
245       pObj->AsImage()->GetImage()->GetDict()->GetDirectObjectFor("Filter");
246   ByteString bsFilter;
247   if (pFilter->IsName())
248     bsFilter = pFilter->AsName()->GetString();
249   else
250     bsFilter = pFilter->AsArray()->GetStringAt(index);
251 
252   unsigned long len = bsFilter.GetLength() + 1;
253   if (buffer && len <= buflen)
254     memcpy(buffer, bsFilter.c_str(), len);
255   return len;
256 }
257 
258 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object,FPDF_PAGE page,FPDF_IMAGEOBJ_METADATA * metadata)259 FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object,
260                               FPDF_PAGE page,
261                               FPDF_IMAGEOBJ_METADATA* metadata) {
262   CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
263   if (!pObj || !pObj->IsImage() || !metadata)
264     return false;
265 
266   RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
267   if (!pImg)
268     return false;
269 
270   metadata->marked_content_id = pObj->m_ContentMark.GetMarkedContentID();
271 
272   const int nPixelWidth = pImg->GetPixelWidth();
273   const int nPixelHeight = pImg->GetPixelHeight();
274   metadata->width = nPixelWidth;
275   metadata->height = nPixelHeight;
276 
277   const float nWidth = pObj->m_Right - pObj->m_Left;
278   const float nHeight = pObj->m_Top - pObj->m_Bottom;
279   constexpr int nPointsPerInch = 72;
280   if (nWidth != 0 && nHeight != 0) {
281     metadata->horizontal_dpi = nPixelWidth / nWidth * nPointsPerInch;
282     metadata->vertical_dpi = nPixelHeight / nHeight * nPointsPerInch;
283   }
284 
285   metadata->bits_per_pixel = 0;
286   metadata->colorspace = FPDF_COLORSPACE_UNKNOWN;
287 
288   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
289   if (!pPage || !pPage->m_pDocument.Get() || !pImg->GetStream())
290     return true;
291 
292   auto pSource = pdfium::MakeRetain<CPDF_DIBSource>();
293   if (!pSource->StartLoadDIBSource(pPage->m_pDocument.Get(), pImg->GetStream(),
294                                    false, nullptr,
295                                    pPage->m_pPageResources.Get())) {
296     return true;
297   }
298 
299   metadata->bits_per_pixel = pSource->GetBPP();
300   if (pSource->GetColorSpace())
301     metadata->colorspace = pSource->GetColorSpace()->GetFamily();
302 
303   return true;
304 }
305