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