summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pdf/framework/libs/pdfClient/image_object.cc34
-rw-r--r--pdf/framework/libs/pdfClient/image_object.h14
-rw-r--r--pdf/framework/libs/pdfClient/jni_conversion.cc130
-rw-r--r--pdf/framework/libs/pdfClient/jni_conversion.h2
4 files changed, 155 insertions, 25 deletions
diff --git a/pdf/framework/libs/pdfClient/image_object.cc b/pdf/framework/libs/pdfClient/image_object.cc
index 61bb85c69..69dedb0bc 100644
--- a/pdf/framework/libs/pdfClient/image_object.cc
+++ b/pdf/framework/libs/pdfClient/image_object.cc
@@ -26,6 +26,23 @@
namespace pdfClient {
+BitmapFormat GetBitmapFormat(int bitmap_format) {
+ switch (bitmap_format) {
+ case FPDFBitmap_BGR: {
+ return BitmapFormat::BGR;
+ }
+ case FPDFBitmap_BGRA: {
+ return BitmapFormat::BGRA;
+ }
+ case FPDFBitmap_BGRx: {
+ return BitmapFormat::BGRx;
+ }
+ default: {
+ return BitmapFormat::Unknown;
+ }
+ }
+}
+
ImageObject::ImageObject() : PageObject(Type::Image) {}
ScopedFPDFPageObject ImageObject::CreateFPDFInstance(FPDF_DOCUMENT document, FPDF_PAGE page) {
@@ -61,31 +78,42 @@ bool ImageObject::UpdateFPDFInstance(FPDF_PAGEOBJECT image_object, FPDF_PAGE pag
return false;
}
+ // Set the updated dimensions.
width_ = FPDFBitmap_GetWidth(bitmap_.get());
height_ = FPDFBitmap_GetHeight(bitmap_.get());
+ // Set the updated bitmap format.
+ bitmap_format_ = GetBitmapFormat(FPDFBitmap_GetFormat(bitmap_.get()));
+
return true;
}
bool ImageObject::PopulateFromFPDFInstance(FPDF_PAGEOBJECT image_object, FPDF_PAGE page) {
- // Get Bitmap
+ // Get bitmap.
bitmap_ = ScopedFPDFBitmap(FPDFImageObj_GetBitmap(image_object));
if (bitmap_.get() == nullptr) {
return false;
}
- // Get Matrix
+ // Get matrix.
if (!GetPageToDeviceMatrix(image_object, page)) {
return false;
}
+ // Get dimensions.
width_ = FPDFBitmap_GetWidth(bitmap_.get());
height_ = FPDFBitmap_GetHeight(bitmap_.get());
+ // Get bitmap format.
+ bitmap_format_ = GetBitmapFormat(FPDFBitmap_GetFormat(bitmap_.get()));
+ if (bitmap_format_ == BitmapFormat::Unknown) {
+ LOGE("Bitmap format unknown");
+ return false;
+ }
return true;
}
-void* ImageObject::GetBitmapReadableBuffer() const {
+void* ImageObject::GetBitmapBuffer() const {
return FPDFBitmap_GetBuffer(bitmap_.get());
}
diff --git a/pdf/framework/libs/pdfClient/image_object.h b/pdf/framework/libs/pdfClient/image_object.h
index 2e3aa9541..e3563ba8e 100644
--- a/pdf/framework/libs/pdfClient/image_object.h
+++ b/pdf/framework/libs/pdfClient/image_object.h
@@ -27,6 +27,13 @@ typedef unsigned int uint;
namespace pdfClient {
+enum class BitmapFormat {
+ Unknown = -1,
+ BGR,
+ BGRA,
+ BGRx,
+};
+
class ImageObject : public PageObject {
public:
ImageObject();
@@ -35,12 +42,13 @@ class ImageObject : public PageObject {
bool UpdateFPDFInstance(FPDF_PAGEOBJECT image_object, FPDF_PAGE page) override;
bool PopulateFromFPDFInstance(FPDF_PAGEOBJECT image_object, FPDF_PAGE page) override;
- void* GetBitmapReadableBuffer() const;
+ void* GetBitmapBuffer() const;
~ImageObject();
- int width_ = 0;
- int height_ = 0;
+ size_t width_ = 0;
+ size_t height_ = 0;
+ BitmapFormat bitmap_format_ = BitmapFormat::Unknown;
ScopedFPDFBitmap bitmap_;
};
diff --git a/pdf/framework/libs/pdfClient/jni_conversion.cc b/pdf/framework/libs/pdfClient/jni_conversion.cc
index c132b6698..46d5b2d9e 100644
--- a/pdf/framework/libs/pdfClient/jni_conversion.cc
+++ b/pdf/framework/libs/pdfClient/jni_conversion.cc
@@ -25,6 +25,7 @@
#include "text_object.h"
using pdfClient::Annotation;
+using pdfClient::BitmapFormat;
using pdfClient::Color;
using pdfClient::Document;
using pdfClient::Font;
@@ -450,7 +451,41 @@ jobject ToJavaGotoLinks(JNIEnv* env, const vector<GotoLink>& links) {
return ToJavaList(env, links, &ToJavaGotoLink);
}
-jobject ToJavaBitmap(JNIEnv* env, void* buffer, int width, int height) {
+void ConvertBgrToRgba(uint32_t* rgba_pixel_array, uint8_t* bgr_pixel_array, size_t rgba_stride,
+ size_t bgr_stride, size_t width, size_t height) {
+ for (size_t y = 0; y < height; y++) {
+ uint32_t* rgba_row_ptr = rgba_pixel_array + y * (rgba_stride / 4);
+ uint8_t* bgr_row_ptr = bgr_pixel_array + y * (bgr_stride);
+ for (size_t x = 0; x < width; x++) {
+ // Extract BGR components stored.
+ uint8_t blue = bgr_row_ptr[x * 3];
+ uint8_t green = bgr_row_ptr[x * 3 + 1];
+ uint8_t red = bgr_row_ptr[x * 3 + 2];
+ // Storing java bitmap components RGBA in little-endian.
+ rgba_row_ptr[x] = (0xFF << 24) | (blue << 16) | (green << 8) | red;
+ }
+ }
+}
+
+void ConvertBgraToRgba(uint32_t* rgba_pixel_array, uint8_t* bgra_pixel_array, size_t rgba_stride,
+ size_t bgra_stride, size_t width, size_t height, bool ignore_alpha) {
+ for (size_t y = 0; y < height; y++) {
+ uint32_t* rgba_row_ptr = rgba_pixel_array + y * (rgba_stride / 4);
+ uint8_t* bgra_row_ptr = bgra_pixel_array + y * (bgra_stride);
+ for (size_t x = 0; x < width; x++) {
+ // Extract BGR components and determine alpha based on ignore_alpha flag.
+ uint8_t blue = bgra_row_ptr[x * 4];
+ uint8_t green = bgra_row_ptr[x * 4 + 1];
+ uint8_t red = bgra_row_ptr[x * 4 + 2];
+ uint8_t alpha = ignore_alpha ? 0xFF : bgra_row_ptr[x * 4 + 3];
+ // Storing java bitmap components RGBA in little-endian.
+ rgba_row_ptr[x] = (alpha << 24) | (blue << 16) | (green << 8) | red;
+ }
+ }
+}
+
+jobject ToJavaBitmap(JNIEnv* env, void* buffer, BitmapFormat bitmap_format, size_t width,
+ size_t height, size_t native_stride) {
// Find Java Bitmap class
static jclass bitmap_class = GetPermClassRef(env, kBitmap);
@@ -469,16 +504,41 @@ jobject ToJavaBitmap(JNIEnv* env, void* buffer, int width, int height) {
jobject java_bitmap =
env->CallStaticObjectMethod(bitmap_class, create_bitmap, width, height, argb8888);
- // Lock the Bitmap pixels for copying
+ // Copy the buffer data into java bitmap.
+ AndroidBitmapInfo bitmap_info;
+ AndroidBitmap_getInfo(env, java_bitmap, &bitmap_info);
+ size_t java_stride = bitmap_info.stride;
+
void* bitmap_pixels;
if (AndroidBitmap_lockPixels(env, java_bitmap, &bitmap_pixels) < 0) {
return NULL;
}
- // Copy the buffer data into java Bitmap.
- std::memcpy(bitmap_pixels, buffer, width * height); // 4 bytes per pixel (ARGB_8888)
+ uint32_t* java_pixel_array = static_cast<uint32_t*>(bitmap_pixels);
+ uint8_t* native_pixel_array = static_cast<uint8_t*>(buffer);
+ switch (bitmap_format) {
+ case BitmapFormat::BGR: {
+ ConvertBgrToRgba(java_pixel_array, native_pixel_array, java_stride, native_stride,
+ width, height);
+ break;
+ }
+ case BitmapFormat::BGRA: {
+ ConvertBgraToRgba(java_pixel_array, native_pixel_array, java_stride, native_stride,
+ width, height, false);
+ break;
+ }
+ case BitmapFormat::BGRx: {
+ ConvertBgraToRgba(java_pixel_array, native_pixel_array, java_stride, native_stride,
+ width, height, true);
+ break;
+ }
+ default: {
+ LOGE("Bitmap format unknown!");
+ AndroidBitmap_unlockPixels(env, java_bitmap);
+ return NULL;
+ }
+ }
- // Unlock the Bitmap pixels
AndroidBitmap_unlockPixels(env, java_bitmap);
return java_bitmap;
@@ -682,11 +742,17 @@ jobject ToJavaPdfImageObject(JNIEnv* env, const ImageObject* image_object) {
static jmethodID init_image =
env->GetMethodID(image_object_class, "<init>", funcsig("V", kBitmap).c_str());
- // Get Bitmap readable buffer from ImageObject Data.
- void* buffer = image_object->GetBitmapReadableBuffer();
-
// Create Java Bitmap from Native Bitmap Buffer.
- jobject java_bitmap = ToJavaBitmap(env, buffer, image_object->width_, image_object->height_);
+ void* buffer = image_object->GetBitmapBuffer();
+ BitmapFormat bitmap_format = image_object->bitmap_format_;
+ size_t width = image_object->width_;
+ size_t height = image_object->height_;
+ int stride = FPDFBitmap_GetStride(image_object->bitmap_.get());
+ jobject java_bitmap = ToJavaBitmap(env, buffer, bitmap_format, width, height, stride);
+ if (java_bitmap == NULL) {
+ LOGE("To java bitmap conversion failed!");
+ return NULL;
+ }
// Create Java PdfImageObject Instance.
jobject java_image_object = env->NewObject(image_object_class, init_image, java_bitmap);
@@ -934,6 +1000,23 @@ std::unique_ptr<PathObject> ToNativePathObject(JNIEnv* env, jobject java_path_ob
return path_object;
}
+void CopyRgbaToBgra(uint8_t* rgba_pixel_array, size_t rgba_stride, uint32_t* bgra_pixel_array,
+ size_t bgra_stride, size_t width, size_t height) {
+ for (size_t y = 0; y < height; y++) {
+ uint8_t* rgba_row_ptr = rgba_pixel_array + y * rgba_stride;
+ uint32_t* bgra_row_ptr = bgra_pixel_array + y * (bgra_stride / 4);
+ for (size_t x = 0; x < width; x++) {
+ // Extract RGBA components stored.
+ uint8_t red = rgba_row_ptr[x * 4];
+ uint8_t green = rgba_row_ptr[x * 4 + 1];
+ uint8_t blue = rgba_row_ptr[x * 4 + 2];
+ uint8_t alpha = rgba_row_ptr[x * 4 + 3];
+ // Storing native bitmap components BGRA in little-endian.
+ bgra_row_ptr[x] = (alpha << 24) | (red << 16) | (green << 8) | blue;
+ }
+ }
+}
+
std::unique_ptr<ImageObject> ToNativeImageObject(JNIEnv* env, jobject java_image_object) {
// Create ImageObject Data Instance.
auto image_object = std::make_unique<ImageObject>();
@@ -946,21 +1029,34 @@ std::unique_ptr<ImageObject> ToNativeImageObject(JNIEnv* env, jobject java_image
env->GetMethodID(image_object_class, "getBitmap", funcsig(kBitmap).c_str());
jobject java_bitmap = env->CallObjectMethod(java_image_object, get_bitmap);
- // Create an FPDF_BITMAP from the Android Bitmap.
+ // Get android bitmap info.
+ AndroidBitmapInfo bitmap_info;
+ AndroidBitmap_getInfo(env, java_bitmap, &bitmap_info);
+ if (bitmap_info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
+ LOGE("Android bitmap is not in RGBA_8888 format");
+ return nullptr;
+ }
+ size_t bitmap_width = bitmap_info.width;
+ size_t bitmap_height = bitmap_info.height;
+ size_t java_stride = bitmap_info.stride;
+
+ // Create ImageObject data bitmap.
+ image_object->bitmap_ = ScopedFPDFBitmap(FPDFBitmap_Create(bitmap_width, bitmap_height, 1));
+ size_t native_stride = FPDFBitmap_GetStride(image_object->bitmap_.get());
+
+ // Copy pixels from android bitmap.
void* bitmap_pixels;
if (AndroidBitmap_lockPixels(env, java_bitmap, &bitmap_pixels) < 0) {
+ LOGE("Android bitmap lock pixels failed!");
return nullptr;
}
- AndroidBitmapInfo bitmap_info;
- AndroidBitmap_getInfo(env, java_bitmap, &bitmap_info);
- const int stride = bitmap_info.width * 4;
+ uint8_t* java_pixel_array = static_cast<uint8_t*>(bitmap_pixels);
+ uint32_t* native_pixel_array = static_cast<uint32_t*>(image_object->GetBitmapBuffer());
- // Set ImageObject Data Bitmap
- image_object->bitmap_ = ScopedFPDFBitmap(FPDFBitmap_CreateEx(
- bitmap_info.width, bitmap_info.height, FPDFBitmap_BGRA, bitmap_pixels, stride));
+ CopyRgbaToBgra(java_pixel_array, java_stride, native_pixel_array, native_stride, bitmap_width,
+ bitmap_height);
- // Unlock the Android Bitmap
AndroidBitmap_unlockPixels(env, java_bitmap);
return image_object;
diff --git a/pdf/framework/libs/pdfClient/jni_conversion.h b/pdf/framework/libs/pdfClient/jni_conversion.h
index 2b679405b..30b784250 100644
--- a/pdf/framework/libs/pdfClient/jni_conversion.h
+++ b/pdf/framework/libs/pdfClient/jni_conversion.h
@@ -117,8 +117,6 @@ jobject ToJavaGotoLink(JNIEnv* env, const GotoLink link);
jobject ToJavaGotoLinks(JNIEnv* env, const vector<GotoLink>& links);
-jobject ToJavaBitmap(JNIEnv* env, void* buffer, int width, int height);
-
jobject ToJavaColor(JNIEnv* env, Color color);
jfloatArray ToJavaFloatArray(JNIEnv* env, const float arr[], size_t length);