Home | History | Annotate | Download | only in pdf
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "PdfUtils.h"
     18 
     19 #include "jni.h"
     20 #include <nativehelper/JNIHelp.h>
     21 #include "GraphicsJNI.h"
     22 #include "SkBitmap.h"
     23 #include "SkMatrix.h"
     24 #include "fpdfview.h"
     25 
     26 #include "core_jni_helpers.h"
     27 #include <vector>
     28 #include <utils/Log.h>
     29 #include <unistd.h>
     30 #include <sys/types.h>
     31 #include <unistd.h>
     32 
     33 namespace android {
     34 
     35 static const int RENDER_MODE_FOR_DISPLAY = 1;
     36 static const int RENDER_MODE_FOR_PRINT = 2;
     37 
     38 static struct {
     39     jfieldID x;
     40     jfieldID y;
     41 } gPointClassInfo;
     42 
     43 static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPtr,
     44         jint pageIndex, jobject outSize) {
     45     FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
     46 
     47     FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
     48     if (!page) {
     49         jniThrowException(env, "java/lang/IllegalStateException",
     50                 "cannot load page");
     51         return -1;
     52     }
     53 
     54     double width = 0;
     55     double height = 0;
     56 
     57     int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
     58     if (!result) {
     59         jniThrowException(env, "java/lang/IllegalStateException",
     60                     "cannot get page size");
     61         return -1;
     62     }
     63 
     64     env->SetIntField(outSize, gPointClassInfo.x, width);
     65     env->SetIntField(outSize, gPointClassInfo.y, height);
     66 
     67     return reinterpret_cast<jlong>(page);
     68 }
     69 
     70 static void nativeClosePage(JNIEnv* env, jclass thiz, jlong pagePtr) {
     71     FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
     72     FPDF_ClosePage(page);
     73 }
     74 
     75 static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
     76         jobject jbitmap, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom,
     77         jlong transformPtr, jint renderMode) {
     78     FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
     79 
     80     SkBitmap skBitmap;
     81     GraphicsJNI::getSkBitmap(env, jbitmap, &skBitmap);
     82 
     83     const int stride = skBitmap.width() * 4;
     84 
     85     FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap.width(), skBitmap.height(),
     86             FPDFBitmap_BGRA, skBitmap.getPixels(), stride);
     87 
     88     int renderFlags = FPDF_REVERSE_BYTE_ORDER;
     89     if (renderMode == RENDER_MODE_FOR_DISPLAY) {
     90         renderFlags |= FPDF_LCD_TEXT;
     91     } else if (renderMode == RENDER_MODE_FOR_PRINT) {
     92         renderFlags |= FPDF_PRINTING;
     93     }
     94 
     95     SkMatrix matrix = *reinterpret_cast<SkMatrix*>(transformPtr);
     96     SkScalar transformValues[6];
     97     if (!matrix.asAffine(transformValues)) {
     98         jniThrowException(env, "java/lang/IllegalArgumentException",
     99                 "transform matrix has perspective. Only affine matrices are allowed.");
    100         return;
    101     }
    102 
    103     FS_MATRIX transform = {transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
    104                            transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
    105                            transformValues[SkMatrix::kATransX],
    106                            transformValues[SkMatrix::kATransY]};
    107 
    108     FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
    109 
    110     FPDF_RenderPageBitmapWithMatrix(bitmap, page, &transform, &clip, renderFlags);
    111 
    112     skBitmap.notifyPixelsChanged();
    113 }
    114 
    115 static const JNINativeMethod gPdfRenderer_Methods[] = {
    116     {"nativeCreate", "(IJ)J", (void*) nativeOpen},
    117     {"nativeClose", "(J)V", (void*) nativeClose},
    118     {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
    119     {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
    120     {"nativeRenderPage", "(JJLandroid/graphics/Bitmap;IIIIJI)V", (void*) nativeRenderPage},
    121     {"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize},
    122     {"nativeClosePage", "(J)V", (void*) nativeClosePage}
    123 };
    124 
    125 int register_android_graphics_pdf_PdfRenderer(JNIEnv* env) {
    126     int result = RegisterMethodsOrDie(
    127             env, "android/graphics/pdf/PdfRenderer", gPdfRenderer_Methods,
    128             NELEM(gPdfRenderer_Methods));
    129 
    130     jclass clazz = FindClassOrDie(env, "android/graphics/Point");
    131     gPointClassInfo.x = GetFieldIDOrDie(env, clazz, "x", "I");
    132     gPointClassInfo.y = GetFieldIDOrDie(env, clazz, "y", "I");
    133 
    134     return result;
    135 };
    136 
    137 };
    138