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 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 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 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 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 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 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 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 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 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 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 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 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