Home | History | Annotate | Download | only in fpdfsdk
      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