1aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov/*
2aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov * Copyright (C) 2013 The Android Open Source Project
3aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov *
4aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
5aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov * you may not use this file except in compliance with the License.
6aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov * You may obtain a copy of the License at
7aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov *
8aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
9aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov *
10aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software
11aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
12aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov * See the License for the specific language governing permissions and
14aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov * limitations under the License.
15aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov */
16aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
17aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganovpackage android.print.pdf;
18aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
19c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmannimport android.annotation.IntRange;
20c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmannimport android.annotation.NonNull;
21aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganovimport android.content.Context;
22aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganovimport android.graphics.Rect;
236811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslavimport android.graphics.pdf.PdfDocument;
24aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganovimport android.print.PrintAttributes;
25aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganovimport android.print.PrintAttributes.Margins;
26aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganovimport android.print.PrintAttributes.MediaSize;
27aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
28aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov/**
29c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann * This class is a helper for creating a PDF file for given print attributes. It is useful for
30c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann * implementing printing via the native Android graphics APIs.
316811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * <p>
32c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann * This class computes the page width, page height, and content rectangle from the provided print
33c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann * attributes and these precomputed values can be accessed via {@link #getPageWidth()},
34c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann * {@link #getPageHeight()}, and {@link #getPageContentRect()}, respectively. The
35c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann * {@link #startPage(int)} methods creates pages whose
36c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann * {@link android.graphics.pdf.PdfDocument.PageInfo PageInfo} is initialized with the precomputed
37c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann * values for width, height, and content rectangle.
386811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * <p>
396811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * A typical use of the APIs looks like this:
406811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * </p>
416811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * <pre>
426811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * // open a new document
436811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * PrintedPdfDocument document = new PrintedPdfDocument(context,
446811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav *         printAttributes);
456811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav *
466811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * // start a page
476811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * Page page = document.startPage(0);
486811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav *
496811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * // draw something on the page
506811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * View content = getContentView();
516811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * content.draw(page.getCanvas());
526811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav *
536811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * // finish the page
546811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * document.finishPage(page);
556811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * . . .
566811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * // add more pages
576811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * . . .
586811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * // write the document content
596811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * document.writeTo(getOutputStream());
606811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav *
616811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * //close the document
626811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * document.close();
636811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav * </pre>
64aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov */
656811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslavpublic class PrintedPdfDocument extends PdfDocument {
66aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    private static final int MILS_PER_INCH = 1000;
67aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    private static final int POINTS_IN_INCH = 72;
68aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
696811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav    private final int mPageWidth;
706811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav    private final int mPageHeight;
716811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav    private final Rect mContentRect;
72aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
73aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    /**
746811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav     * Creates a new document.
75aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * <p>
76aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * <strong>Note:</strong> You must close the document after you are
776811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav     * done by calling {@link #close()}.
78aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * </p>
79aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     *
80aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * @param context Context instance for accessing resources.
81aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * @param attributes The print attributes.
82aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     */
83c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann    public PrintedPdfDocument(@NonNull Context context, @NonNull PrintAttributes attributes) {
84aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov        MediaSize mediaSize = attributes.getMediaSize();
85aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
86aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov        // Compute the size of the target canvas from the attributes.
876811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav        mPageWidth = (int) (((float) mediaSize.getWidthMils() / MILS_PER_INCH)
88aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov                * POINTS_IN_INCH);
896811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav        mPageHeight = (int) (((float) mediaSize.getHeightMils() / MILS_PER_INCH)
90aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov                * POINTS_IN_INCH);
91aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
92aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov        // Compute the content size from the attributes.
93651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav        Margins minMargins = attributes.getMinMargins();
946811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav        final int marginLeft = (int) (((float) minMargins.getLeftMils() / MILS_PER_INCH)
95aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov                * POINTS_IN_INCH);
96651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav        final int marginTop = (int) (((float) minMargins.getTopMils() / MILS_PER_INCH)
97aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov                * POINTS_IN_INCH);
98651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav        final int marginRight = (int) (((float) minMargins.getRightMils() / MILS_PER_INCH)
99aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov                * POINTS_IN_INCH);
100651dd4e6ee6510caf9f15c51094a11121af17ec2Svetoslav        final int marginBottom = (int) (((float) minMargins.getBottomMils() / MILS_PER_INCH)
101aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov                * POINTS_IN_INCH);
1026811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav        mContentRect = new Rect(marginLeft, marginTop, mPageWidth - marginRight,
1036811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav                mPageHeight - marginBottom);
104aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    }
105aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
106aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    /**
107c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * Starts a new page. The page is created using width, height and content rectangle computed
108c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * from the print attributes passed in the constructor and the given page number to create an
109c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * appropriate {@link android.graphics.pdf.PdfDocument.PageInfo PageInfo}.
110aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * <p>
111c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * After the page is created you can draw arbitrary content on the page's canvas which you can
112c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * get by calling {@link android.graphics.pdf.PdfDocument.Page#getCanvas() Page.getCanvas()}.
113aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * After you are done drawing the content you should finish the page by calling
114c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * {@link #finishPage(Page)}. After the page is finished you should no longer access the page or
115c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * its canvas.
116aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * </p>
117aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * <p>
118c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * <strong>Note:</strong> Do not call this method after {@link #close()}. Also do not call this
119c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * method if the last page returned by this method is not finished by calling
120c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * {@link #finishPage(Page)}.
121aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * </p>
122aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     *
123c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann     * @param pageNumber The page number. Must be a non negative.
124aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * @return A blank page.
125aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     *
126aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     * @see #finishPage(Page)
127aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     */
128c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann    public @NonNull Page startPage(@IntRange(from = 0) int pageNumber) {
129d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        PageInfo pageInfo = new PageInfo
1306811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav                .Builder(mPageWidth, mPageHeight, pageNumber)
1316811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav                .setContentRect(mContentRect)
132d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                .create();
1336811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav        return startPage(pageInfo);
134aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    }
135aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
136aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    /**
1376811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav     * Gets the page width.
138aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     *
1396811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav     * @return The page width in PostScript points (1/72th of an inch).
140aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     */
141c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann    public @IntRange(from = 0) int getPageWidth() {
1426811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav        return mPageWidth;
143aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    }
144aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
145aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    /**
1466811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav     * Gets the page height.
147aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     *
1486811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav     * @return The page height in PostScript points (1/72th of an inch).
149aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     */
150c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann    public @IntRange(from = 0) int getPageHeight() {
1516811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav        return mPageHeight;
152aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    }
153aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov
154aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    /**
1556811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav     * Gets the content rectangle. This is the area of the page that
1566811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav     * contains printed data and is relative to the page top left.
157aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     *
1586811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav     * @return The content rectangle.
159aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov     */
160c43639c3067dda5df189fb3cbf14f256c17e677dPhilip P. Moltmann    public @NonNull Rect getPageContentRect() {
1616811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav        return mContentRect;
162aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov    }
163aec1417ca9eb63209668ac17da90cf8a07c6076cSvetoslav Ganov}
164