blob: 4842e35c768a9f88df0f5b8155b1005803daa7e1 [file] [log] [blame]
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001// 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.
Lei Zhanga6d9f0e2015-06-13 00:48:38 -07004
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07005// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
Lei Zhangb4e7f302015-11-06 15:52:32 -08007#include "public/fpdf_edit.h"
8
dsinclair39c62fd2016-09-29 12:49:17 -07009#include "core/fpdfapi/cpdf_modulemgr.h"
dsinclair41872fa2016-10-04 11:29:35 -070010#include "core/fpdfapi/page/cpdf_image.h"
11#include "core/fpdfapi/page/cpdf_imageobject.h"
Jane Liuca898292017-08-16 11:25:35 -040012#include "core/fpdfapi/page/cpdf_page.h"
dsinclair41872fa2016-10-04 11:29:35 -070013#include "core/fpdfapi/page/cpdf_pageobject.h"
Jane Liube63ab92017-08-09 14:09:34 -040014#include "core/fpdfapi/parser/cpdf_array.h"
15#include "core/fpdfapi/parser/cpdf_name.h"
Jane Liuca898292017-08-16 11:25:35 -040016#include "core/fpdfapi/render/cpdf_dibsource.h"
dsinclair114e46a2016-09-29 17:18:21 -070017#include "fpdfsdk/fsdk_define.h"
tsepez36eb4bd2016-10-03 15:24:27 -070018#include "third_party/base/ptr_util.h"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070019
Lei Zhangcbd89572017-03-15 17:35:47 -070020namespace {
thestigc54bb432016-07-29 19:34:20 -070021
Jane Liuca898292017-08-16 11:25:35 -040022// These checks ensure the consistency of colorspace values across core/ and
23// public/.
24static_assert(PDFCS_DEVICEGRAY == FPDF_COLORSPACE_DEVICEGRAY,
25 "PDFCS_DEVICEGRAY value mismatch");
26static_assert(PDFCS_DEVICERGB == FPDF_COLORSPACE_DEVICERGB,
27 "PDFCS_DEVICERGB value mismatch");
28static_assert(PDFCS_DEVICECMYK == FPDF_COLORSPACE_DEVICECMYK,
29 "PDFCS_DEVICECMYK value mismatch");
30static_assert(PDFCS_CALGRAY == FPDF_COLORSPACE_CALGRAY,
31 "PDFCS_CALGRAY value mismatch");
32static_assert(PDFCS_CALRGB == FPDF_COLORSPACE_CALRGB,
33 "PDFCS_CALRGB value mismatch");
34static_assert(PDFCS_LAB == FPDF_COLORSPACE_LAB, "PDFCS_LAB value mismatch");
35static_assert(PDFCS_ICCBASED == FPDF_COLORSPACE_ICCBASED,
36 "PDFCS_ICCBASED value mismatch");
37static_assert(PDFCS_SEPARATION == FPDF_COLORSPACE_SEPARATION,
38 "PDFCS_SEPARATION value mismatch");
39static_assert(PDFCS_DEVICEN == FPDF_COLORSPACE_DEVICEN,
40 "PDFCS_DEVICEN value mismatch");
41static_assert(PDFCS_INDEXED == FPDF_COLORSPACE_INDEXED,
42 "PDFCS_INDEXED value mismatch");
43static_assert(PDFCS_PATTERN == FPDF_COLORSPACE_PATTERN,
44 "PDFCS_PATTERN value mismatch");
45
Lei Zhangcbd89572017-03-15 17:35:47 -070046bool LoadJpegHelper(FPDF_PAGE* pages,
47 int nCount,
48 FPDF_PAGEOBJECT image_object,
49 FPDF_FILEACCESS* fileAccess,
50 bool inlineJpeg) {
Andrew Weintraub21f88ff2017-05-10 13:19:52 -040051 if (!image_object || !fileAccess)
tsepez4cf55152016-11-02 14:37:54 -070052 return false;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070053
Dan Sinclair0b950422017-09-21 15:49:49 -040054 RetainPtr<IFX_SeekableReadStream> pFile = MakeSeekableReadStream(fileAccess);
Nicolas Pena46abb662017-05-17 17:23:22 -040055 CPDF_ImageObject* pImgObj = static_cast<CPDF_ImageObject*>(image_object);
Andrew Weintraub21f88ff2017-05-10 13:19:52 -040056
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 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -070063 }
rbpotterf085db32016-12-14 11:44:31 -080064
65 if (inlineJpeg)
66 pImgObj->GetImage()->SetJpegImageInline(pFile);
67 else
68 pImgObj->GetImage()->SetJpegImage(pFile);
wileyryae858aa42017-05-31 14:49:05 -050069 pImgObj->SetDirty(true);
tsepez4cf55152016-11-02 14:37:54 -070070 return true;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070071}
72
Lei Zhangcbd89572017-03-15 17:35:47 -070073} // namespace
74
Dan Sinclair00d2ad12017-08-10 14:13:02 -040075FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
Lei Zhangcbd89572017-03-15 17:35:47 -070076FPDFPageObj_NewImageObj(FPDF_DOCUMENT document) {
77 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
78 if (!pDoc)
79 return nullptr;
80
Tom Sepez7d4f6a82017-03-31 17:10:34 -070081 auto pImageObj = pdfium::MakeUnique<CPDF_ImageObject>();
82 pImageObj->SetImage(pdfium::MakeRetain<CPDF_Image>(pDoc));
83 return pImageObj.release();
Lei Zhangcbd89572017-03-15 17:35:47 -070084}
85
Dan Sinclair00d2ad12017-08-10 14:13:02 -040086FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
rbpotterf085db32016-12-14 11:44:31 -080087FPDFImageObj_LoadJpegFile(FPDF_PAGE* pages,
88 int nCount,
89 FPDF_PAGEOBJECT image_object,
90 FPDF_FILEACCESS* fileAccess) {
Lei Zhangcbd89572017-03-15 17:35:47 -070091 return LoadJpegHelper(pages, nCount, image_object, fileAccess, false);
rbpotterf085db32016-12-14 11:44:31 -080092}
93
Dan Sinclair00d2ad12017-08-10 14:13:02 -040094FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
rbpotterf085db32016-12-14 11:44:31 -080095FPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages,
96 int nCount,
97 FPDF_PAGEOBJECT image_object,
98 FPDF_FILEACCESS* fileAccess) {
Lei Zhangcbd89572017-03-15 17:35:47 -070099 return LoadJpegHelper(pages, nCount, image_object, fileAccess, true);
rbpotterf085db32016-12-14 11:44:31 -0800100}
101
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400102FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
103FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object,
104 double a,
105 double b,
106 double c,
107 double d,
108 double e,
109 double f) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700110 if (!image_object)
tsepez4cf55152016-11-02 14:37:54 -0700111 return false;
thestigc54bb432016-07-29 19:34:20 -0700112
Nicolas Pena46abb662017-05-17 17:23:22 -0400113 CPDF_ImageObject* pImgObj = static_cast<CPDF_ImageObject*>(image_object);
Dan Sinclair05df0752017-03-14 14:43:42 -0400114 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)));
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700117 pImgObj->CalcBoundingBox();
wileyryae858aa42017-05-31 14:49:05 -0500118 pImgObj->SetDirty(true);
tsepez4cf55152016-11-02 14:37:54 -0700119 return true;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700120}
121
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400122FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
123FPDFImageObj_SetBitmap(FPDF_PAGE* pages,
124 int nCount,
125 FPDF_PAGEOBJECT image_object,
126 FPDF_BITMAP bitmap) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700127 if (!image_object || !bitmap || !pages)
tsepez4cf55152016-11-02 14:37:54 -0700128 return false;
thestigc54bb432016-07-29 19:34:20 -0700129
Nicolas Pena46abb662017-05-17 17:23:22 -0400130 CPDF_ImageObject* pImgObj = static_cast<CPDF_ImageObject*>(image_object);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700131 for (int index = 0; index < nCount; index++) {
Tom Sepezdb0be962015-10-16 14:00:21 -0700132 CPDF_Page* pPage = CPDFPageFromFPDFPage(pages[index]);
thestigc54bb432016-07-29 19:34:20 -0700133 if (pPage)
thestigf41d9dc2016-08-05 22:34:58 -0700134 pImgObj->GetImage()->ResetCache(pPage, nullptr);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700135 }
Dan Sinclair0b950422017-09-21 15:49:49 -0400136 RetainPtr<CFX_DIBitmap> holder(CFXBitmapFromFPDFBitmap(bitmap));
Tom Sepezf0799fe2017-03-28 09:31:32 -0700137 pImgObj->GetImage()->SetImage(holder);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700138 pImgObj->CalcBoundingBox();
wileyryae858aa42017-05-31 14:49:05 -0500139 pImgObj->SetDirty(true);
tsepez4cf55152016-11-02 14:37:54 -0700140 return true;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700141}
Jane Liu28fb7ba2017-08-02 21:45:57 -0400142
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400143FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV
Jane Liu28fb7ba2017-08-02 21:45:57 -0400144FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object) {
145 CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
146 if (!pObj || !pObj->IsImage())
147 return nullptr;
148
Dan Sinclair0b950422017-09-21 15:49:49 -0400149 RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
Jane Liu28fb7ba2017-08-02 21:45:57 -0400150 if (!pImg)
151 return nullptr;
152
Dan Sinclair0b950422017-09-21 15:49:49 -0400153 RetainPtr<CFX_DIBSource> pSource = pImg->LoadDIBSource();
Jane Liu28fb7ba2017-08-02 21:45:57 -0400154 if (!pSource)
155 return nullptr;
156
Dan Sinclair0b950422017-09-21 15:49:49 -0400157 RetainPtr<CFX_DIBitmap> pBitmap;
Jane Liu28fb7ba2017-08-02 21:45:57 -0400158 // 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}
Jane Liu548334e2017-08-03 16:33:40 -0400169
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400170FPDF_EXPORT unsigned long FPDF_CALLCONV
Jane Liu548334e2017-08-03 16:33:40 -0400171FPDFImageObj_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
Dan Sinclair0b950422017-09-21 15:49:49 -0400178 RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
Jane Liu548334e2017-08-03 16:33:40 -0400179 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
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400189FPDF_EXPORT unsigned long FPDF_CALLCONV
Jane Liu548334e2017-08-03 16:33:40 -0400190FPDFImageObj_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
Dan Sinclair0b950422017-09-21 15:49:49 -0400197 RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
Jane Liu548334e2017-08-03 16:33:40 -0400198 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}
Jane Liube63ab92017-08-09 14:09:34 -0400211
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400212FPDF_EXPORT int FPDF_CALLCONV
Jane Liube63ab92017-08-09 14:09:34 -0400213FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object) {
214 CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object);
215 if (!pObj || !pObj->IsImage())
216 return 0;
217
Dan Sinclair0b950422017-09-21 15:49:49 -0400218 RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
Jane Liube63ab92017-08-09 14:09:34 -0400219 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
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400235FPDF_EXPORT unsigned long FPDF_CALLCONV
Jane Liube63ab92017-08-09 14:09:34 -0400236FPDFImageObj_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");
Ryan Harrison275e2602017-09-18 14:23:18 -0400246 ByteString bsFilter;
Jane Liube63ab92017-08-09 14:09:34 -0400247 if (pFilter->IsName())
Lei Zhang0733a1b2017-08-31 12:36:31 -0700248 bsFilter = pFilter->AsName()->GetString();
Jane Liube63ab92017-08-09 14:09:34 -0400249 else
Lei Zhang0733a1b2017-08-31 12:36:31 -0700250 bsFilter = pFilter->AsArray()->GetStringAt(index);
Jane Liube63ab92017-08-09 14:09:34 -0400251
Lei Zhang0733a1b2017-08-31 12:36:31 -0700252 unsigned long len = bsFilter.GetLength() + 1;
253 if (buffer && len <= buflen)
254 memcpy(buffer, bsFilter.c_str(), len);
255 return len;
Jane Liube63ab92017-08-09 14:09:34 -0400256}
Jane Liuca898292017-08-16 11:25:35 -0400257
258FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
259FPDFImageObj_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
Dan Sinclair0b950422017-09-21 15:49:49 -0400266 RetainPtr<CPDF_Image> pImg = pObj->AsImage()->GetImage();
Jane Liuca898292017-08-16 11:25:35 -0400267 if (!pImg)
268 return false;
269
270 const int nPixelWidth = pImg->GetPixelWidth();
271 const int nPixelHeight = pImg->GetPixelHeight();
272 metadata->width = nPixelWidth;
273 metadata->height = nPixelHeight;
274
275 const float nWidth = pObj->m_Right - pObj->m_Left;
276 const float nHeight = pObj->m_Top - pObj->m_Bottom;
277 constexpr int nPointsPerInch = 72;
278 if (nWidth != 0 && nHeight != 0) {
279 metadata->horizontal_dpi = nPixelWidth / nWidth * nPointsPerInch;
280 metadata->vertical_dpi = nPixelHeight / nHeight * nPointsPerInch;
281 }
282
283 metadata->bits_per_pixel = 0;
284 metadata->colorspace = FPDF_COLORSPACE_UNKNOWN;
285
286 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
287 if (!pPage || !pPage->m_pDocument.Get() || !pImg->GetStream())
288 return true;
289
290 auto pSource = pdfium::MakeRetain<CPDF_DIBSource>();
291 if (!pSource->StartLoadDIBSource(pPage->m_pDocument.Get(), pImg->GetStream(),
292 false, nullptr,
293 pPage->m_pPageResources.Get())) {
294 return true;
295 }
296
297 metadata->bits_per_pixel = pSource->GetBPP();
298 if (pSource->GetColorSpace())
299 metadata->colorspace = pSource->GetColorSpace()->GetFamily();
300
301 return true;
302}