From be63ab97e0385b4024ef84fda79fc84dc111ab23 Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Wed, 9 Aug 2017 14:09:34 -0400 Subject: API and test for retrieving image filters from image objects Added FPDFImageObj_GetImageFilterCount() and FPDFImageObj_GetImageFilters() for retrieving image filters of image objects. * Added a corresponding embedder test. * Changed the filter of an image object in embedded_image.pdf from DCTDecode to ASCIIHexDecode + DCTDecode, so we have a test case for images with more than one filter. Bug=pdfium:677 Change-Id: I398790a2cad33fea4ca16a0eb0889c04caa6b962 Reviewed-on: https://pdfium-review.googlesource.com/10130 Reviewed-by: Lei Zhang Reviewed-by: dsinclair Commit-Queue: Jane Liu --- fpdfsdk/fpdfedit_embeddertest.cpp | 46 ++++++++++++++++++++++++++++++++++ fpdfsdk/fpdfeditimg.cpp | 45 +++++++++++++++++++++++++++++++++ fpdfsdk/fpdfview_c_api_test.c | 2 ++ public/fpdf_edit.h | 25 ++++++++++++++++++ testing/resources/embedded_images.pdf | Bin 27089 -> 34279 bytes 5 files changed, 118 insertions(+) diff --git a/fpdfsdk/fpdfedit_embeddertest.cpp b/fpdfsdk/fpdfedit_embeddertest.cpp index c381b25efa..e62ef2149b 100644 --- a/fpdfsdk/fpdfedit_embeddertest.cpp +++ b/fpdfsdk/fpdfedit_embeddertest.cpp @@ -1038,3 +1038,49 @@ TEST_F(FPDFEditEmbeddertest, DestroyPageObject) { // There should be no memory leaks with a call to FPDFPageObj_Destroy(). FPDFPageObj_Destroy(rect); } + +TEST_F(FPDFEditEmbeddertest, GetImageFilters) { + EXPECT_TRUE(OpenDocument("embedded_images.pdf")); + FPDF_PAGE page = LoadPage(0); + ASSERT_TRUE(page); + + // Verify that retrieving the filter of a non-image object would fail. + FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32); + ASSERT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj)); + ASSERT_EQ(0, FPDFImageObj_GetImageFilterCount(obj)); + EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0)); + + // Verify the returned filter string for an image object with a single filter. + obj = FPDFPage_GetObject(page, 33); + ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj)); + ASSERT_EQ(1, FPDFImageObj_GetImageFilterCount(obj)); + unsigned long len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0); + std::vector buf(len); + EXPECT_EQ(24u, FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len)); + EXPECT_STREQ(L"FlateDecode", + GetPlatformWString(reinterpret_cast(buf.data())) + .c_str()); + EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0)); + + // Verify all the filters for an image object with a list of filters. + obj = FPDFPage_GetObject(page, 38); + ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj)); + ASSERT_EQ(2, FPDFImageObj_GetImageFilterCount(obj)); + len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0); + buf.clear(); + buf.resize(len); + EXPECT_EQ(30u, FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len)); + EXPECT_STREQ(L"ASCIIHexDecode", + GetPlatformWString(reinterpret_cast(buf.data())) + .c_str()); + + len = FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0); + buf.clear(); + buf.resize(len); + EXPECT_EQ(20u, FPDFImageObj_GetImageFilter(obj, 1, buf.data(), len)); + EXPECT_STREQ(L"DCTDecode", + GetPlatformWString(reinterpret_cast(buf.data())) + .c_str()); + + UnloadPage(page); +} diff --git a/fpdfsdk/fpdfeditimg.cpp b/fpdfsdk/fpdfeditimg.cpp index 0d0c54604b..b4254e97c6 100644 --- a/fpdfsdk/fpdfeditimg.cpp +++ b/fpdfsdk/fpdfeditimg.cpp @@ -10,6 +10,8 @@ #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" #include "core/fpdfapi/page/cpdf_pageobject.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_name.h" #include "fpdfsdk/fsdk_define.h" #include "third_party/base/ptr_util.h" @@ -179,3 +181,46 @@ FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object, return len; } + +DLLEXPORT int STDCALL +FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object) { + CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object); + if (!pObj || !pObj->IsImage()) + return 0; + + CFX_RetainPtr pImg = pObj->AsImage()->GetImage(); + if (!pImg) + return 0; + + CPDF_Dictionary* pDict = pImg->GetDict(); + CPDF_Object* pFilter = pDict ? pDict->GetDirectObjectFor("Filter") : nullptr; + if (!pFilter) + return 0; + + if (pFilter->IsArray()) + return pFilter->AsArray()->GetCount(); + if (pFilter->IsName()) + return 1; + + return 0; +} + +DLLEXPORT unsigned long STDCALL +FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object, + int index, + void* buffer, + unsigned long buflen) { + if (index < 0 || index >= FPDFImageObj_GetImageFilterCount(image_object)) + return 0; + + CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object); + CPDF_Object* pFilter = + pObj->AsImage()->GetImage()->GetDict()->GetDirectObjectFor("Filter"); + CFX_WideString wsFilters; + if (pFilter->IsName()) + wsFilters = pFilter->AsName()->GetUnicodeText(); + else + wsFilters = pFilter->AsArray()->GetUnicodeTextAt(index); + + return Utf16EncodeMaybeCopyAndReturnLength(wsFilters, buffer, buflen); +} diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c index ef5b804baa..8276eb64b7 100644 --- a/fpdfsdk/fpdfview_c_api_test.c +++ b/fpdfsdk/fpdfview_c_api_test.c @@ -136,6 +136,8 @@ int CheckPDFiumCApi() { CHK(FPDFImageObj_GetBitmap); CHK(FPDFImageObj_GetImageDataDecoded); CHK(FPDFImageObj_GetImageDataRaw); + CHK(FPDFImageObj_GetImageFilterCount); + CHK(FPDFImageObj_GetImageFilter); CHK(FPDFPageObj_CreateNewPath); CHK(FPDFPageObj_CreateNewRect); CHK(FPDFPath_SetStrokeColor); diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h index aab48af3f1..54127d80ea 100644 --- a/public/fpdf_edit.h +++ b/public/fpdf_edit.h @@ -336,6 +336,31 @@ FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object, void* buffer, unsigned long buflen); +// Get the number of filters (i.e. decoders) of the image in |image_object|. +// +// image_object - handle to an image object. +// +// Returns the number of |image_object|'s filters. +DLLEXPORT int STDCALL +FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object); + +// Get the filter at |index| of |image_object|'s list of filters. Note that the +// filters need to be applied in order, i.e. the first filter should be applied +// first, then the second, etc. |buffer| is only modified if |buflen| is longer +// than the length of the filter string. +// +// image_object - handle to an image object. +// index - the index of the filter requested. +// buffer - buffer for holding filter string, encoded in UTF16-LE. +// buflen - length of the buffer. +// +// Returns the length of the filter string. +DLLEXPORT unsigned long STDCALL +FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object, + int index, + void* buffer, + unsigned long buflen); + // Create a new path object at an initial position. // // x - initial horizontal position. diff --git a/testing/resources/embedded_images.pdf b/testing/resources/embedded_images.pdf index 81845822a4..82adbeaa4c 100644 Binary files a/testing/resources/embedded_images.pdf and b/testing/resources/embedded_images.pdf differ -- cgit v1.2.3