PdfRenderer.java revision 95b6fd8b7af276069cbc415da3499d5ab4873c32
12961769ea94f69c191a2dd785b2504666c7292d0Svetoslav/*
22961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * Copyright (C) 2014 The Android Open Source Project
32961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
42961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * Licensed under the Apache License, Version 2.0 (the "License");
52961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * you may not use this file except in compliance with the License.
62961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * You may obtain a copy of the License at
72961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
82961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *      http://www.apache.org/licenses/LICENSE-2.0
92961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
102961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * Unless required by applicable law or agreed to in writing, software
112961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * distributed under the License is distributed on an "AS IS" BASIS,
122961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * See the License for the specific language governing permissions and
142961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * limitations under the License.
152961769ea94f69c191a2dd785b2504666c7292d0Svetoslav */
162961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
172961769ea94f69c191a2dd785b2504666c7292d0Svetoslavpackage android.graphics.pdf;
182961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
192961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.annotation.IntDef;
202961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.annotation.NonNull;
212961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.annotation.Nullable;
222961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.graphics.Bitmap;
232961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.graphics.Bitmap.Config;
242961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.graphics.Matrix;
252961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.graphics.Point;
262961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.graphics.Rect;
272961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.os.ParcelFileDescriptor;
282961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.system.ErrnoException;
292961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.system.OsConstants;
302961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport dalvik.system.CloseGuard;
312961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport libcore.io.Libcore;
322961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
332961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport java.io.IOException;
342961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport java.lang.annotation.Retention;
352961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport java.lang.annotation.RetentionPolicy;
362961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
372961769ea94f69c191a2dd785b2504666c7292d0Svetoslav/**
382961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * <p>
392961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * This class enables rendering a PDF document. This class is not thread safe.
402961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * </p>
412961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * <p>
422961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * If you want to render a PDF, you create a renderer and for every page you want
432961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * to render, you open the page, render it, and close the page. After you are done
442961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * with rendering, you close the renderer. After the renderer is closed it should not
452961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * be used anymore. Note that the pages are rendered one by one, i.e. you can have
462961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * only a single page opened at any given time.
472961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * </p>
482961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * <p>
492961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * A typical use of the APIs to render a PDF looks like this:
502961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * </p>
512961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * <pre>
522961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * // create a new renderer
532961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
542961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
552961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * // let us just render all pages
562961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * final int pageCount = renderer.getPageCount();
572961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * for (int i = 0; i < pageCount; i++) {
582961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *     Page page = renderer.openPage(i);
592961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
602961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *     // say we render for showing on the screen
6195b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav *     page.render(mBitmap, null, null, Page.RENDER_MODE_FOR_DISPLAY);
622961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
632961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *     // do stuff with the bitmap
642961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
6595b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav *     // close the page
6695b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav *     page.close();
672961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * }
682961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
692961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * // close the renderer
702961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * renderer.close();
712961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * </pre>
722961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
732961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * @see #close()
742961769ea94f69c191a2dd785b2504666c7292d0Svetoslav */
752961769ea94f69c191a2dd785b2504666c7292d0Svetoslavpublic final class PdfRenderer implements AutoCloseable {
762961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private final CloseGuard mCloseGuard = CloseGuard.get();
772961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
782961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private final Point mTempPoint = new Point();
792961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
802961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private final long mNativeDocument;
812961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
822961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private final int mPageCount;
832961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
842961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private ParcelFileDescriptor mInput;
852961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
862961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private Page mCurrentPage;
872961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
882961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /** @hide */
892961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    @IntDef({
902961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        Page.RENDER_MODE_FOR_DISPLAY,
912961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        Page.RENDER_MODE_FOR_PRINT
922961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    })
932961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    @Retention(RetentionPolicy.SOURCE)
942961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public @interface RenderMode {}
952961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
962961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
972961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * Creates a new instance.
982961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * <p>
992961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
1002961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * i.e. its data being randomly accessed, e.g. pointing to a file.
1012961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * </p>
1022961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * <p>
1032961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * <strong>Note:</strong> This class takes ownership of the passed in file descriptor
1042961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * and is responsible for closing it when the renderer is closed.
1052961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * </p>
1062961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     *
1072961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * @param input Seekable file descriptor to read from.
1082961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
1092961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException {
1102961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        if (input == null) {
1112961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            throw new NullPointerException("input cannot be null");
1122961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
1132961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1142961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        final long size;
1152961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        try {
1162961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
1172961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            size = Libcore.os.fstat(input.getFileDescriptor()).st_size;
1182961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        } catch (ErrnoException ee) {
1192961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            throw new IllegalArgumentException("file descriptor not seekable");
1202961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
1212961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1222961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mInput = input;
1232961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mNativeDocument = nativeCreate(mInput.getFd(), size);
1242961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mPageCount = nativeGetPageCount(mNativeDocument);
1252961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mCloseGuard.open("close");
1262961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
1272961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1282961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
1292961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * Closes this renderer. You should not use this instance
1302961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * after this method is called.
1312961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
1322961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public void close() {
1332961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfClosed();
1342961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfPageOpened();
1352961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        doClose();
1362961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
1372961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1382961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
1392961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * Gets the number of pages in the document.
1402961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     *
1412961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * @return The page count.
1422961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
1432961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public int getPageCount() {
1442961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfClosed();
1452961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        return mPageCount;
1462961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
1472961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1482961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
1492961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * Gets whether the document prefers to be scaled for printing.
1502961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * You should take this info account if the document is rendered
1512961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * for printing and the target media size differs from the page
1522961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * size.
1532961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     *
1542961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * @return If to scale the document.
1552961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
1562961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public boolean shouldScaleForPrinting() {
1572961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfClosed();
1582961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        return nativeScaleForPrinting(mNativeDocument);
1592961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
1602961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1612961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
1622961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * Opens a page for rendering.
1632961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     *
1642961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * @param index The page index.
1652961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * @return A page that can be rendered.
1662961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     *
16795b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav     * @see android.graphics.pdf.PdfRenderer.Page#close() PdfRenderer.Page.close()
1682961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
1692961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public Page openPage(int index) {
1702961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfClosed();
1712961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfPageOpened();
1722961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mCurrentPage = new Page(index);
1732961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        return mCurrentPage;
1742961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
1752961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1762961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    @Override
1772961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    protected void finalize() throws Throwable {
1782961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        try {
1792961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mCloseGuard.warnIfOpen();
1802961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (mInput != null) {
1812961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                doClose();
1822961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
1832961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        } finally {
1842961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            super.finalize();
1852961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
1862961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
1872961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1882961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private void doClose() {
1892961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        if (mCurrentPage != null) {
1902961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mCurrentPage.close();
1912961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mCurrentPage = null;
1922961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
1932961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        nativeClose(mNativeDocument);
1942961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        try {
1952961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mInput.close();
1962961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        } catch (IOException ioe) {
1972961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            /* ignore - best effort */
1982961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
1992961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mInput = null;
2002961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mCloseGuard.close();
2012961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
2022961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2032961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private void throwIfClosed() {
2042961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        if (mInput == null) {
2052961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            throw new IllegalStateException("Already closed");
2062961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2072961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
2082961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2092961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private void throwIfPageOpened() {
2102961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        if (mCurrentPage != null) {
2112961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            throw new IllegalStateException("Current page not closed");
2122961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2132961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
2142961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2152961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
2162961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * This class represents a PDF document page for rendering.
2172961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
21895b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav    public final class Page implements AutoCloseable {
21995b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav
22095b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        private final CloseGuard mCloseGuard = CloseGuard.get();
2212961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2222961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
2232961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Mode to render the content for display on a screen.
2242961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
2252961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public static final int RENDER_MODE_FOR_DISPLAY = 1;
2262961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2272961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
2282961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Mode to render the content for printing.
2292961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
2302961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public static final int RENDER_MODE_FOR_PRINT = 2;
2312961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2322961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        private final int mIndex;
2332961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        private final int mWidth;
2342961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        private final int mHeight;
2352961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2362961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        private long mNativePage;
2372961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2382961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        private Page(int index) {
2392961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            Point size = mTempPoint;
2402961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
2412961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mIndex = index;
2422961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mWidth = size.x;
2432961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mHeight = size.y;
24495b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            mCloseGuard.open("close");
2452961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2462961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2472961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
2482961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Gets the page index.
2492961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         *
2502961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @return The index.
2512961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
2522961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public int getIndex() {
2532961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            return  mIndex;
2542961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2552961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2562961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
2572961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Gets the page width in points (1/72").
2582961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         *
2592961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @return The width in points.
2602961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
2612961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public int getWidth() {
2622961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            return mWidth;
2632961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2642961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2652961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
2662961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Gets the page height in points (1/72").
2672961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         *
2682961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @return The height in points.
2692961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
2702961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public int getHeight() {
2712961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            return mHeight;
2722961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2732961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2742961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
2752961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Renders a page to a bitmap.
2762961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <p>
2772961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * You may optionally specify a rectangular clip in the bitmap bounds. No rendering
2782961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * outside the clip will be performed, hence it is your responsibility to initialize
2792961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * the bitmap outside the clip.
2802961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * </p>
2812961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <p>
2822961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * You may optionally specify a matrix to transform the content from page coordinates
2832961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * which are in points (1/72") to bitmap coordintates which are in pixels. If this
2842961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * matrix is not provided this method will apply a transformation that will fit the
28595b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         * whole page to the destination clip if provided or the destination bitmap if no
2862961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * clip is provided.
2872961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * </p>
2882961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <p>
2892961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * The clip and transformation are useful for implementing tile rendering where the
2902961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * destination bitmap contains a portion of the image, for example when zooming.
2912961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Another useful application is for printing where the size of the bitmap holding
2922961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * the page is too large and a client can render the page in stripes.
2932961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * </p>
2942961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <p>
2952961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <strong>Note: </strong> The destination bitmap format must be
2962961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * {@link Config#ARGB_8888 ARGB}.
2972961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * </p>
2982961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <p>
2992961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <strong>Note: </strong> The optional transformation matrix must be affine as per
30095b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         * {@link android.graphics.Matrix#isAffine() Matrix.isAffine()}. Hence, you can specify
30195b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         * rotation, scaling, translation but not a perspective transformation.
3022961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * </p>
3032961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         *
3042961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @param destination Destination bitmap to which to render.
3052961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @param destClip Optional clip in the bitmap bounds.
3062961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @param transform Optional transformation to apply when rendering.
3072961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @param renderMode The render mode.
3082961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         *
3092961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @see #RENDER_MODE_FOR_DISPLAY
3102961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @see #RENDER_MODE_FOR_PRINT
3112961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
3122961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public void render(@NonNull Bitmap destination, @Nullable Rect destClip,
3132961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                           @Nullable Matrix transform, @RenderMode int renderMode) {
3142961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (destination.getConfig() != Config.ARGB_8888) {
3152961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                throw new IllegalArgumentException("Unsupported pixel format");
3162961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
3172961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3182961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (destClip != null) {
3192961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                if (destClip.left < 0 || destClip.top < 0
3202961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                        || destClip.right > destination.getWidth()
3212961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                        || destClip.bottom > destination.getHeight()) {
3222961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                    throw new IllegalArgumentException("destBounds not in destination");
3232961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                }
3242961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
3252961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3262961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (transform != null && !transform.isAffine()) {
3272961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                 throw new IllegalArgumentException("transform not affine");
3282961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
3292961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3302961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (renderMode != RENDER_MODE_FOR_PRINT && renderMode != RENDER_MODE_FOR_DISPLAY) {
3312961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                throw new IllegalArgumentException("Unsupported render mode");
3322961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
3332961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3342961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (renderMode == RENDER_MODE_FOR_PRINT && renderMode == RENDER_MODE_FOR_DISPLAY) {
3352961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                throw new IllegalArgumentException("Only single render mode supported");
3362961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
3372961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3382961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            final int contentLeft = (destClip != null) ? destClip.left : 0;
3392961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            final int contentTop = (destClip != null) ? destClip.top : 0;
3402961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            final int contentRight = (destClip != null) ? destClip.right
3412961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                    : destination.getWidth();
3422961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            final int contentBottom = (destClip != null) ? destClip.bottom
3432961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                    : destination.getHeight();
3442961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3452961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            final long transformPtr = (transform != null) ? transform.native_instance : 0;
3462961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3472961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            nativeRenderPage(mNativeDocument, mNativePage, destination.mNativeBitmap, contentLeft,
3482961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                    contentTop, contentRight, contentBottom, transformPtr, renderMode);
3492961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
3502961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
35195b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        /**
35295b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         * Closes this page.
35395b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         *
35495b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         * @see android.graphics.pdf.PdfRenderer#openPage(int)
35595b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         */
35695b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        @Override
35795b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        public void close() {
35895b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            throwIfClosed();
35995b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            doClose();
36095b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        }
36195b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav
36295b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        @Override
36395b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        protected void finalize() throws Throwable {
36495b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            try {
36595b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                mCloseGuard.warnIfOpen();
36695b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                if (mNativePage != 0) {
36795b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                    doClose();
36895b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                }
36995b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            } finally {
37095b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                super.finalize();
37195b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            }
37295b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        }
37395b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav
37495b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        private void doClose() {
3752961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            nativeClosePage(mNativePage);
3762961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mNativePage = 0;
37795b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            mCloseGuard.close();
37895b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        }
37995b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav
38095b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        private void throwIfClosed() {
38195b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            if (mNativePage == 0) {
38295b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                throw new IllegalStateException("Already closed");
38395b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            }
3842961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
3852961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
3862961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3872961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native long nativeCreate(int fd, long size);
3882961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native void nativeClose(long documentPtr);
3892961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native int nativeGetPageCount(long documentPtr);
3902961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native boolean nativeScaleForPrinting(long documentPtr);
3912961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native void nativeRenderPage(long documentPtr, long pagePtr, long destPtr,
3922961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            int destLeft, int destTop, int destRight, int destBottom, long matrixPtr, int renderMode);
3932961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
3942961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            Point outSize);
3952961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native void nativeClosePage(long pagePtr);
3962961769ea94f69c191a2dd785b2504666c7292d0Svetoslav}
397