1/*
2 * Copyright (C) 2013 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
17package android.print.pdf;
18
19import android.annotation.IntRange;
20import android.annotation.NonNull;
21import android.content.Context;
22import android.graphics.Rect;
23import android.graphics.pdf.PdfDocument;
24import android.print.PrintAttributes;
25import android.print.PrintAttributes.Margins;
26import android.print.PrintAttributes.MediaSize;
27
28/**
29 * This class is a helper for creating a PDF file for given print attributes. It is useful for
30 * implementing printing via the native Android graphics APIs.
31 * <p>
32 * This class computes the page width, page height, and content rectangle from the provided print
33 * attributes and these precomputed values can be accessed via {@link #getPageWidth()},
34 * {@link #getPageHeight()}, and {@link #getPageContentRect()}, respectively. The
35 * {@link #startPage(int)} methods creates pages whose
36 * {@link android.graphics.pdf.PdfDocument.PageInfo PageInfo} is initialized with the precomputed
37 * values for width, height, and content rectangle.
38 * <p>
39 * A typical use of the APIs looks like this:
40 * </p>
41 * <pre>
42 * // open a new document
43 * PrintedPdfDocument document = new PrintedPdfDocument(context,
44 *         printAttributes);
45 *
46 * // start a page
47 * Page page = document.startPage(0);
48 *
49 * // draw something on the page
50 * View content = getContentView();
51 * content.draw(page.getCanvas());
52 *
53 * // finish the page
54 * document.finishPage(page);
55 * . . .
56 * // add more pages
57 * . . .
58 * // write the document content
59 * document.writeTo(getOutputStream());
60 *
61 * //close the document
62 * document.close();
63 * </pre>
64 */
65public class PrintedPdfDocument extends PdfDocument {
66    private static final int MILS_PER_INCH = 1000;
67    private static final int POINTS_IN_INCH = 72;
68
69    private final int mPageWidth;
70    private final int mPageHeight;
71    private final Rect mContentRect;
72
73    /**
74     * Creates a new document.
75     * <p>
76     * <strong>Note:</strong> You must close the document after you are
77     * done by calling {@link #close()}.
78     * </p>
79     *
80     * @param context Context instance for accessing resources.
81     * @param attributes The print attributes.
82     */
83    public PrintedPdfDocument(@NonNull Context context, @NonNull PrintAttributes attributes) {
84        MediaSize mediaSize = attributes.getMediaSize();
85
86        // Compute the size of the target canvas from the attributes.
87        mPageWidth = (int) (((float) mediaSize.getWidthMils() / MILS_PER_INCH)
88                * POINTS_IN_INCH);
89        mPageHeight = (int) (((float) mediaSize.getHeightMils() / MILS_PER_INCH)
90                * POINTS_IN_INCH);
91
92        // Compute the content size from the attributes.
93        Margins minMargins = attributes.getMinMargins();
94        final int marginLeft = (int) (((float) minMargins.getLeftMils() / MILS_PER_INCH)
95                * POINTS_IN_INCH);
96        final int marginTop = (int) (((float) minMargins.getTopMils() / MILS_PER_INCH)
97                * POINTS_IN_INCH);
98        final int marginRight = (int) (((float) minMargins.getRightMils() / MILS_PER_INCH)
99                * POINTS_IN_INCH);
100        final int marginBottom = (int) (((float) minMargins.getBottomMils() / MILS_PER_INCH)
101                * POINTS_IN_INCH);
102        mContentRect = new Rect(marginLeft, marginTop, mPageWidth - marginRight,
103                mPageHeight - marginBottom);
104    }
105
106    /**
107     * Starts a new page. The page is created using width, height and content rectangle computed
108     * from the print attributes passed in the constructor and the given page number to create an
109     * appropriate {@link android.graphics.pdf.PdfDocument.PageInfo PageInfo}.
110     * <p>
111     * After the page is created you can draw arbitrary content on the page's canvas which you can
112     * get by calling {@link android.graphics.pdf.PdfDocument.Page#getCanvas() Page.getCanvas()}.
113     * After you are done drawing the content you should finish the page by calling
114     * {@link #finishPage(Page)}. After the page is finished you should no longer access the page or
115     * its canvas.
116     * </p>
117     * <p>
118     * <strong>Note:</strong> Do not call this method after {@link #close()}. Also do not call this
119     * method if the last page returned by this method is not finished by calling
120     * {@link #finishPage(Page)}.
121     * </p>
122     *
123     * @param pageNumber The page number. Must be a non negative.
124     * @return A blank page.
125     *
126     * @see #finishPage(Page)
127     */
128    public @NonNull Page startPage(@IntRange(from = 0) int pageNumber) {
129        PageInfo pageInfo = new PageInfo
130                .Builder(mPageWidth, mPageHeight, pageNumber)
131                .setContentRect(mContentRect)
132                .create();
133        return startPage(pageInfo);
134    }
135
136    /**
137     * Gets the page width.
138     *
139     * @return The page width in PostScript points (1/72th of an inch).
140     */
141    public @IntRange(from = 0) int getPageWidth() {
142        return mPageWidth;
143    }
144
145    /**
146     * Gets the page height.
147     *
148     * @return The page height in PostScript points (1/72th of an inch).
149     */
150    public @IntRange(from = 0) int getPageHeight() {
151        return mPageHeight;
152    }
153
154    /**
155     * Gets the content rectangle. This is the area of the page that
156     * contains printed data and is relative to the page top left.
157     *
158     * @return The content rectangle.
159     */
160    public @NonNull Rect getPageContentRect() {
161        return mContentRect;
162    }
163}
164