From ca89829775fec2968b51fe5abad86bad1b6a277b Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Wed, 16 Aug 2017 11:25:35 -0400 Subject: API and test for retrieving metadata from image objects Added FPDFImageObj_GetImageMetadata() for retriving the image metadata of image objects, including its dimension, DPI, bits per pixel, and colorspace. * Added a corresponding embedder test. Bug=pdfium:677 Change-Id: I4229334d1ac2125b21a46e2e44ea937ea2e94b51 Reviewed-on: https://pdfium-review.googlesource.com/10110 Reviewed-by: Lei Zhang Reviewed-by: dsinclair Commit-Queue: Jane Liu --- core/fpdfapi/render/cpdf_dibsource.h | 1 + fpdfsdk/fpdfedit_embeddertest.cpp | 47 +++++++++++++++++++++++ fpdfsdk/fpdfeditimg.cpp | 72 ++++++++++++++++++++++++++++++++++++ fpdfsdk/fpdfview_c_api_test.c | 1 + public/fpdf_edit.h | 45 ++++++++++++++++++++++ 5 files changed, 166 insertions(+) diff --git a/core/fpdfapi/render/cpdf_dibsource.h b/core/fpdfapi/render/cpdf_dibsource.h index 50e9a038e8..66a6d4e4e8 100644 --- a/core/fpdfapi/render/cpdf_dibsource.h +++ b/core/fpdfapi/render/cpdf_dibsource.h @@ -60,6 +60,7 @@ class CPDF_DIBSource : public CFX_DIBSource { int clip_left, int clip_width) const override; + const CPDF_ColorSpace* GetColorSpace() const { return m_pColorSpace; } uint32_t GetMatteColor() const { return m_MatteColor; } int StartLoadDIBSource(CPDF_Document* pDoc, diff --git a/fpdfsdk/fpdfedit_embeddertest.cpp b/fpdfsdk/fpdfedit_embeddertest.cpp index e62ef2149b..6dc177e2b5 100644 --- a/fpdfsdk/fpdfedit_embeddertest.cpp +++ b/fpdfsdk/fpdfedit_embeddertest.cpp @@ -1084,3 +1084,50 @@ TEST_F(FPDFEditEmbeddertest, GetImageFilters) { UnloadPage(page); } + +TEST_F(FPDFEditEmbeddertest, GetImageMetadata) { + ASSERT_TRUE(OpenDocument("embedded_images.pdf")); + FPDF_PAGE page = LoadPage(0); + ASSERT_TRUE(page); + + // Check that getting the metadata of a null object would fail. + FPDF_IMAGEOBJ_METADATA metadata; + EXPECT_FALSE(FPDFImageObj_GetImageMetadata(nullptr, page, &metadata)); + + // Check that receiving the metadata with a null metadata object would fail. + FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35); + EXPECT_FALSE(FPDFImageObj_GetImageMetadata(obj, page, nullptr)); + + // Check that when retrieving an image object's metadata without passing in + // |page|, all values are correct, with the last two being default values. + ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj)); + ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, nullptr, &metadata)); + EXPECT_EQ(92u, metadata.width); + EXPECT_EQ(68u, metadata.height); + EXPECT_NEAR(96.000000, metadata.horizontal_dpi, 0.001); + EXPECT_NEAR(96.000000, metadata.vertical_dpi, 0.001); + EXPECT_EQ(0u, metadata.bits_per_pixel); + EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace); + + // Verify the metadata of a bitmap image with indexed colorspace. + ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata)); + EXPECT_EQ(92u, metadata.width); + EXPECT_EQ(68u, metadata.height); + EXPECT_NEAR(96.000000, metadata.horizontal_dpi, 0.001); + EXPECT_NEAR(96.000000, metadata.vertical_dpi, 0.001); + EXPECT_EQ(1u, metadata.bits_per_pixel); + EXPECT_EQ(FPDF_COLORSPACE_INDEXED, metadata.colorspace); + + // Verify the metadata of an image with RGB colorspace. + obj = FPDFPage_GetObject(page, 37); + ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj)); + ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata)); + EXPECT_EQ(126u, metadata.width); + EXPECT_EQ(106u, metadata.height); + EXPECT_NEAR(162.173752, metadata.horizontal_dpi, 0.001); + EXPECT_NEAR(162.555878, metadata.vertical_dpi, 0.001); + EXPECT_EQ(24u, metadata.bits_per_pixel); + EXPECT_EQ(FPDF_COLORSPACE_DEVICERGB, metadata.colorspace); + + UnloadPage(page); +} diff --git a/fpdfsdk/fpdfeditimg.cpp b/fpdfsdk/fpdfeditimg.cpp index f19e21c8ff..662ad23d76 100644 --- a/fpdfsdk/fpdfeditimg.cpp +++ b/fpdfsdk/fpdfeditimg.cpp @@ -9,14 +9,40 @@ #include "core/fpdfapi/cpdf_modulemgr.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" +#include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/render/cpdf_dibsource.h" #include "fpdfsdk/fsdk_define.h" #include "third_party/base/ptr_util.h" namespace { +// These checks ensure the consistency of colorspace values across core/ and +// public/. +static_assert(PDFCS_DEVICEGRAY == FPDF_COLORSPACE_DEVICEGRAY, + "PDFCS_DEVICEGRAY value mismatch"); +static_assert(PDFCS_DEVICERGB == FPDF_COLORSPACE_DEVICERGB, + "PDFCS_DEVICERGB value mismatch"); +static_assert(PDFCS_DEVICECMYK == FPDF_COLORSPACE_DEVICECMYK, + "PDFCS_DEVICECMYK value mismatch"); +static_assert(PDFCS_CALGRAY == FPDF_COLORSPACE_CALGRAY, + "PDFCS_CALGRAY value mismatch"); +static_assert(PDFCS_CALRGB == FPDF_COLORSPACE_CALRGB, + "PDFCS_CALRGB value mismatch"); +static_assert(PDFCS_LAB == FPDF_COLORSPACE_LAB, "PDFCS_LAB value mismatch"); +static_assert(PDFCS_ICCBASED == FPDF_COLORSPACE_ICCBASED, + "PDFCS_ICCBASED value mismatch"); +static_assert(PDFCS_SEPARATION == FPDF_COLORSPACE_SEPARATION, + "PDFCS_SEPARATION value mismatch"); +static_assert(PDFCS_DEVICEN == FPDF_COLORSPACE_DEVICEN, + "PDFCS_DEVICEN value mismatch"); +static_assert(PDFCS_INDEXED == FPDF_COLORSPACE_INDEXED, + "PDFCS_INDEXED value mismatch"); +static_assert(PDFCS_PATTERN == FPDF_COLORSPACE_PATTERN, + "PDFCS_PATTERN value mismatch"); + bool LoadJpegHelper(FPDF_PAGE* pages, int nCount, FPDF_PAGEOBJECT image_object, @@ -226,3 +252,49 @@ FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object, return Utf16EncodeMaybeCopyAndReturnLength(wsFilters, buffer, buflen); } + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object, + FPDF_PAGE page, + FPDF_IMAGEOBJ_METADATA* metadata) { + CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(image_object); + if (!pObj || !pObj->IsImage() || !metadata) + return false; + + CFX_RetainPtr pImg = pObj->AsImage()->GetImage(); + if (!pImg) + return false; + + const int nPixelWidth = pImg->GetPixelWidth(); + const int nPixelHeight = pImg->GetPixelHeight(); + metadata->width = nPixelWidth; + metadata->height = nPixelHeight; + + const float nWidth = pObj->m_Right - pObj->m_Left; + const float nHeight = pObj->m_Top - pObj->m_Bottom; + constexpr int nPointsPerInch = 72; + if (nWidth != 0 && nHeight != 0) { + metadata->horizontal_dpi = nPixelWidth / nWidth * nPointsPerInch; + metadata->vertical_dpi = nPixelHeight / nHeight * nPointsPerInch; + } + + metadata->bits_per_pixel = 0; + metadata->colorspace = FPDF_COLORSPACE_UNKNOWN; + + CPDF_Page* pPage = CPDFPageFromFPDFPage(page); + if (!pPage || !pPage->m_pDocument.Get() || !pImg->GetStream()) + return true; + + auto pSource = pdfium::MakeRetain(); + if (!pSource->StartLoadDIBSource(pPage->m_pDocument.Get(), pImg->GetStream(), + false, nullptr, + pPage->m_pPageResources.Get())) { + return true; + } + + metadata->bits_per_pixel = pSource->GetBPP(); + if (pSource->GetColorSpace()) + metadata->colorspace = pSource->GetColorSpace()->GetFamily(); + + return true; +} diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c index 88b7465744..4dd4995cd2 100644 --- a/fpdfsdk/fpdfview_c_api_test.c +++ b/fpdfsdk/fpdfview_c_api_test.c @@ -138,6 +138,7 @@ int CheckPDFiumCApi() { CHK(FPDFImageObj_GetImageDataRaw); CHK(FPDFImageObj_GetImageFilterCount); CHK(FPDFImageObj_GetImageFilter); + CHK(FPDFImageObj_GetImageMetadata); CHK(FPDFPageObj_CreateNewPath); CHK(FPDFPageObj_CreateNewRect); CHK(FPDFPath_SetStrokeColor); diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h index f75744599f..c547f07890 100644 --- a/public/fpdf_edit.h +++ b/public/fpdf_edit.h @@ -20,6 +20,20 @@ #define FPDF_GetRValue(argb) ((uint8_t)((argb) >> 16)) #define FPDF_GetAValue(argb) ((uint8_t)((argb) >> 24)) +// Refer to PDF Reference version 1.7 table 4.12 for all color space families. +#define FPDF_COLORSPACE_UNKNOWN 0 +#define FPDF_COLORSPACE_DEVICEGRAY 1 +#define FPDF_COLORSPACE_DEVICERGB 2 +#define FPDF_COLORSPACE_DEVICECMYK 3 +#define FPDF_COLORSPACE_CALGRAY 4 +#define FPDF_COLORSPACE_CALRGB 5 +#define FPDF_COLORSPACE_LAB 6 +#define FPDF_COLORSPACE_ICCBASED 7 +#define FPDF_COLORSPACE_SEPARATION 8 +#define FPDF_COLORSPACE_DEVICEN 9 +#define FPDF_COLORSPACE_INDEXED 10 +#define FPDF_COLORSPACE_PATTERN 11 + // The page object constants. #define FPDF_PAGEOBJ_UNKNOWN 0 #define FPDF_PAGEOBJ_TEXT 1 @@ -47,6 +61,21 @@ #define FPDF_PRINTMODE_POSTSCRIPT2 2 #define FPDF_PRINTMODE_POSTSCRIPT3 3 +typedef struct FPDF_IMAGEOBJ_METADATA { + // The image width in pixels. + unsigned int width; + // The image height in pixels. + unsigned int height; + // The image's horizontal pixel-per-inch. + float horizontal_dpi; + // The image's vertical pixel-per-inch. + float vertical_dpi; + // The number of bits used to represent each pixel. + unsigned int bits_per_pixel; + // The image's colorspace. See above for the list of FPDF_COLORSPACE_*. + int colorspace; +} FPDF_IMAGEOBJ_METADATA; + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -366,6 +395,22 @@ FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object, void* buffer, unsigned long buflen); +// Get the image metadata of |image_object|, including dimension, DPI, bits per +// pixel, and colorspace. If the |image_object| is not an image object or if it +// does not have an image, then the return value will be false. Otherwise, +// failure to retrieve any specific parameter would result in its value being 0. +// +// image_object - handle to an image object. +// page - handle to the page that |image_object| is on. Required for +// retrieving the image's bits per pixel and colorspace. +// metadata - receives the image metadata; must not be NULL. +// +// Returns true if successful. +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object, + FPDF_PAGE page, + FPDF_IMAGEOBJ_METADATA* metadata); + // Create a new path object at an initial position. // // x - initial horizontal position. -- cgit v1.2.3