Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 923c633c authored by Svetoslav Ganov's avatar Svetoslav Ganov Committed by Svetoslav
Browse files

Generate PDF from Canvas.

This change adds simple APIs that enable an Android application
to generate a PDF document by drawing content on a canvas.

Change-Id: Iddcd126b3af37c73d99262f6b276caa07b998c1d
parent 4602a709
Loading
Loading
Loading
Loading
+16 −0
Original line number Original line Diff line number Diff line
@@ -18370,6 +18370,22 @@ package android.preference {
}
}
package android.print.pdf {
  public class PdfDocument {
    ctor public PdfDocument();
    method public boolean appendPage(android.print.pdf.PdfDocument.PdfPage);
    method public android.print.pdf.PdfDocument.PdfPage createPage(android.graphics.Rect, android.graphics.Rect);
    method public android.print.pdf.PdfDocument.PdfPage createPage(android.graphics.Rect, android.graphics.Rect, android.graphics.Matrix);
    method public void finalize() throws java.lang.Throwable;
    method public void write(java.io.OutputStream);
  }
  public class PdfDocument.PdfPage extends android.graphics.Canvas {
  }
}
package android.provider {
package android.provider {
  public final class AlarmClock {
  public final class AlarmClock {
+158 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.print.pdf;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;

import java.io.OutputStream;

/**
 * This class enables generating a PDF document from native Android
 * content. A client uses a factory method in this class to create a
 * blank page, a {@link Canvas}, on which native Android content can
 * be drawn. Then the client draws arbitrary content on the page via
 * the {@link Canvas} APIs. Next the client adds the page to the
 * document. After all pages have been added the client calls the
 * {@link #write(OutputStream)} method to emit a PDF document.
 * </p>
 * <p>
 * A typical use of the APIs looks like this:
 * </p>
 * <pre>
 * // Create a document.
 * PdfDocument document = new PdfDocument();
 *
 * // Create a blank page.
 * PdfPage page = document.createPage(pageBounds, contentBounds,
 *         initialTransform);
 *
 * // Draw the content view on the page.
 * content.draw(page);
 *
 * // Add the page to the document.
 * document.appendPage(page);
 *
 * // Write the document to a file.
 * document.write(createOutputStream());
 * </pre>
 */
public class PdfDocument {

    private final byte[] mChunk = new byte[1024];

    private final int mNativeDocument;

    /**
     * Creates a new instance.
     */
    public PdfDocument() {
        mNativeDocument = native_createDocument();
    }

    /**
     * Creates a PDF page with the specified <code>pageSize</code> and
     * <code>contentSize</code> Anything outside of the drawing area will be
     * clipped.
     *
     * @param pageSize The page size in points.
     * @param contentSize The content size in points.
     * @return A blank page.
     */
    public PdfPage createPage(Rect pageSize, Rect contentSize) {
        return new PdfPage(pageSize, contentSize, new Matrix());
    }

    /**
     * Creates a PDF page with the specified <code>pageSize</code>,
     * <code>contentSize</code>, and <code>initialTransform</code>. The
     * initial transform is combined with the content size to determine
     * the drawing area. Anything outside of the drawing area will be
     * clipped. The initial transform may be useful to move the origin
     * to account for applying a margin, scale, or rotation.
     *
     * @param pageSize The page size in points.
     * @param contentSize The content size in points.
     * @param initialTransform The initial transform to apply to the page.
     * @return A blank page.
     */
    public PdfPage createPage(Rect pageSize, Rect contentSize, Matrix initialTransform) {
        return new PdfPage(pageSize, contentSize, initialTransform);
    }

    /**
     * Append the page to the document.
     *
     * @param page The page.
     * @return Whether the addition succeeded.
     */
    public boolean appendPage(PdfPage page) {
        return native_appendPage(mNativeDocument, page.mNativeCanvas);
    }

    /**
     * Writes the document to an output stream.
     *
     * @param out The output stream.
     */
    public void write(OutputStream out) {
        native_write(mNativeDocument, out, mChunk);
    }

    @Override
    public void finalize() throws Throwable {
        try {
            if (mNativeDocument != 0) {
                native_finalize(mNativeDocument);
            }
        } finally {
            super.finalize();
        }
    }

    /**
     * This class represents a page in a PDF document. It is a
     * {@link Canvas} on which any arbitrary content can be drawn.
     *
     * @see PdfDocument
     */
    public class PdfPage extends Canvas {

        private PdfPage(Rect pageSize, Rect contentSize, Matrix initialTransform) {
            super(native_createPage(pageSize, contentSize, initialTransform.native_instance));
        }

        @Override
        public void setBitmap(Bitmap bitmap) {
            throw new UnsupportedOperationException(
                    "Cannot set bitmap device on a pdf canvas!");
        }
    }

    private native int native_createDocument();

    private native void native_finalize(int document);

    private native boolean native_appendPage(int document, int page);

    private native void native_write(int document, OutputStream out, byte[] chunk);

    private static native int native_createPage(Rect pageSize,
            Rect contentSize, int nativeMatrix);
}
+2 −0
Original line number Original line Diff line number Diff line
@@ -143,6 +143,7 @@ extern int register_android_os_FileObserver(JNIEnv *env);
extern int register_android_os_FileUtils(JNIEnv *env);
extern int register_android_os_FileUtils(JNIEnv *env);
extern int register_android_os_UEventObserver(JNIEnv* env);
extern int register_android_os_UEventObserver(JNIEnv* env);
extern int register_android_os_MemoryFile(JNIEnv* env);
extern int register_android_os_MemoryFile(JNIEnv* env);
extern int register_android_print_PdfDocument(JNIEnv* env);
extern int register_android_net_LocalSocketImpl(JNIEnv* env);
extern int register_android_net_LocalSocketImpl(JNIEnv* env);
extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_net_TrafficStats(JNIEnv* env);
extern int register_android_net_TrafficStats(JNIEnv* env);
@@ -1170,6 +1171,7 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_os_SELinux),
    REG_JNI(register_android_os_SELinux),
    REG_JNI(register_android_os_Trace),
    REG_JNI(register_android_os_Trace),
    REG_JNI(register_android_os_UEventObserver),
    REG_JNI(register_android_os_UEventObserver),
    REG_JNI(register_android_print_PdfDocument),
    REG_JNI(register_android_net_LocalSocketImpl),
    REG_JNI(register_android_net_LocalSocketImpl),
    REG_JNI(register_android_net_NetworkUtils),
    REG_JNI(register_android_net_NetworkUtils),
    REG_JNI(register_android_net_TrafficStats),
    REG_JNI(register_android_net_TrafficStats),
+91 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "jni.h"
#include "GraphicsJNI.h"
#include <android_runtime/AndroidRuntime.h>

#include "SkCanvas.h"
#include "SkPDFDevice.h"
#include "SkPDFDocument.h"
#include "SkRect.h"
#include "SkSize.h"
#include "CreateJavaOutputStreamAdaptor.h"

namespace android {

class PdfDocumentGlue {
public:

    static SkPDFDocument* createDocument(JNIEnv* env, jobject clazz) {
        return new SkPDFDocument();
    }

    static void finalize(JNIEnv* env, jobject thiz, SkPDFDocument* document) {
        delete document;
    }

    static SkCanvas* createPage(JNIEnv* env, jobject thiz, jobject pageSize,
            jobject contentSize, const SkMatrix* initialTransformation) {
        NPE_CHECK_RETURN_ZERO(env, pageSize);
        NPE_CHECK_RETURN_ZERO(env, contentSize);

        SkIRect skPageSizeRect;
        GraphicsJNI::jrect_to_irect(env, pageSize, &skPageSizeRect);
        SkISize skPageSize = SkISize::Make(skPageSizeRect.width(),
                skPageSizeRect.height());

        SkIRect skContentRect;
        GraphicsJNI::jrect_to_irect(env, contentSize, &skContentRect);
        SkISize skContentSize = SkISize::Make(skContentRect.width(),
                skContentRect.height());

        SkPDFDevice* skPdfDevice = new SkPDFDevice(skPageSize,
                skContentSize, *initialTransformation);

        return new SkCanvas(skPdfDevice);
    }

    static bool appendPage(JNIEnv* env, jobject thiz,
            SkPDFDocument* document, SkCanvas* page) {
        SkPDFDevice* device = reinterpret_cast<SkPDFDevice*>(page->getDevice());
        return document->appendPage(device);
    }

    static void write(JNIEnv* env, jobject clazz, SkPDFDocument* document,
            jobject out, jbyteArray chunk) {
        SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
        document->emitPDF(skWStream);
        delete skWStream;
    }
};

static JNINativeMethod gPdfDocumentMethods[] = {
    {"native_createDocument", "()I", (void*) PdfDocumentGlue::createDocument},
    {"native_finalize", "(I)V", (void*) PdfDocumentGlue::finalize},
    {"native_createPage", "(Landroid/graphics/Rect;Landroid/graphics/Rect;I)I",
            (void*) PdfDocumentGlue::createPage},
    {"native_appendPage", "(II)Z", (void*) PdfDocumentGlue::appendPage},
    {"native_write", "(ILjava/io/OutputStream;[B)V", (void*) PdfDocumentGlue::write}
};

int register_android_print_PdfDocument(JNIEnv* env) {
    int result = android::AndroidRuntime::registerNativeMethods(
            env, "android/print/pdf/PdfDocument", gPdfDocumentMethods,
            NELEM(gPdfDocumentMethods));
    return result;
}
} // end namespace Andorid
+5 −3
Original line number Original line Diff line number Diff line
@@ -38,7 +38,8 @@ import javax.microedition.khronos.opengles.GL;
 */
 */
public class Canvas {
public class Canvas {
    // assigned in constructors or setBitmap, freed in finalizer
    // assigned in constructors or setBitmap, freed in finalizer
    int mNativeCanvas;
    /** @hide */
    public int mNativeCanvas;
    
    
    // may be null
    // may be null
    private Bitmap mBitmap;
    private Bitmap mBitmap;
@@ -133,7 +134,8 @@ public class Canvas {
        mDensity = bitmap.mDensity;
        mDensity = bitmap.mDensity;
    }
    }


    Canvas(int nativeCanvas) {
    /** @hide */
    public Canvas(int nativeCanvas) {
        if (nativeCanvas == 0) {
        if (nativeCanvas == 0) {
            throw new IllegalStateException();
            throw new IllegalStateException();
        }
        }