1 /* 2 * Copyright (C) 2024 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 package android.graphics.pdf; 18 19 import android.graphics.Bitmap; 20 import android.graphics.Rect; 21 import android.graphics.pdf.content.PdfPageGotoLinkContent; 22 import android.graphics.pdf.models.FormWidgetInfo; 23 import android.graphics.pdf.models.jni.LinkRects; 24 import android.graphics.pdf.models.jni.LoadPdfResult; 25 import android.graphics.pdf.models.jni.MatchRects; 26 import android.graphics.pdf.models.jni.PageSelection; 27 import android.graphics.pdf.models.jni.SelectionBoundary; 28 import android.graphics.pdf.utils.StrictModeUtils; 29 import android.os.ParcelFileDescriptor; 30 31 import java.util.List; 32 33 /** 34 * This class accesses the PdfClient tools to manipulate and render a PDF document. One instance of 35 * this class corresponds to one PDF document, loads it within PdfClient and keeps an internal 36 * reference to the resulting object, to be re-used in subsequent calls. 37 * 38 * <p>This class is mostly a JNI gateway to PdfClient. 39 * 40 * @hide 41 */ 42 public class PdfDocumentProxy { 43 private static final String TAG = "PdfDocument"; 44 45 private static final String LIB_NAME = "pdfclient"; 46 47 /** Internal reference to a native pointer to a Document object. */ 48 private final long mPdfDocPtr; 49 50 private final int mNumPages; 51 52 /** Constructs a PdfDocument. Do not call directly from java, use {@link #createFromFd}. */ PdfDocumentProxy(long pdfDocPtr, int numPages)53 protected PdfDocumentProxy(long pdfDocPtr, int numPages) { 54 this.mPdfDocPtr = pdfDocPtr; 55 this.mNumPages = numPages; 56 } 57 58 /** 59 * Tries to load a PdfDocument from native file descriptor. 60 * 61 * @return a LoadPdfResult of status LOADED containing the PdfDocument, 62 * or, an empty LoadPdfResult of a different status indicating failure. 63 */ createFromFd(int fd, String password)64 public static native LoadPdfResult createFromFd(int fd, String password); 65 66 /** 67 * Loads the PdfClient binary library used to render PDF documents. The library will only be 68 * loaded once so subsequent calls after the first will have no effect. This may be used to 69 * preload the library before use. 70 */ loadLibPdf()71 public static void loadLibPdf() { 72 // TODO(b/324549320): Cleanup if bypassing is not required 73 StrictModeUtils.bypass(() -> System.loadLibrary(LIB_NAME)); 74 } 75 getPdfDocPtr()76 public long getPdfDocPtr() { 77 return mPdfDocPtr; 78 } 79 getNumPages()80 public int getNumPages() { 81 return mNumPages; 82 } 83 84 /** Destroys the PDF document and release resources held by PdfClient. */ destroy()85 public native void destroy(); 86 87 /** 88 * Tries to save this PdfDocument to the given native file descriptor, which must be open for 89 * write or append. 90 * 91 * @return true on success 92 */ saveToFd(int fd)93 public native boolean saveToFd(int fd); 94 95 /** 96 * Saves the current state of this {@link PdfDocument} to the given, writable, file descriptor. 97 * The given file descriptor is closed by this function. 98 * 99 * @param destination the file descriptor to write to 100 * @return true on success 101 */ saveAs(ParcelFileDescriptor destination)102 public boolean saveAs(ParcelFileDescriptor destination) { 103 return saveToFd(destination.detachFd()); 104 } 105 106 /** 107 * Returns the width of the given page of the PDF. This is measured in points, but we 108 * zoom-to-fit, so it doesn't matter. 109 */ getPageWidth(int pageNum)110 public native int getPageWidth(int pageNum); 111 112 /** 113 * Returns the height of the given page of the PDF. This is measured in points, but we 114 * zoom-to-fit, so it doesn't matter. 115 */ getPageHeight(int pageNum)116 public native int getPageHeight(int pageNum); 117 118 /** 119 * Renders a page to a bitmap. 120 * 121 * @param pageNum the page number of the page to be rendered 122 * @param clipLeft the left coordinate of the clipping boundary in bitmap coordinates 123 * @param clipTop the top coordinate of the clipping boundary in bitmap coordinates 124 * @param clipRight the right coordinate of the clipping boundary in bitmap coordinates 125 * @param clipBottom the bottom coordinate of the clipping boundary in bitmap coordinates 126 * @param transform an affine transform matrix in the form of an array. 127 * @see android.graphics.Matrix#getValues(float[]) 128 * @param renderMode the render mode 129 * @param showAnnotTypes Bitmask of renderFlags to indicate the types of annotations to 130 * be rendered 131 * @param renderFormFields true to included PDF form content in the output 132 * @return true if the page was rendered into the destination bitmap 133 */ render( int pageNum, Bitmap bitmap, int clipLeft, int clipTop, int clipRight, int clipBottom, float[] transform, int renderMode, int showAnnotTypes, boolean renderFormFields)134 public native boolean render( 135 int pageNum, 136 Bitmap bitmap, 137 int clipLeft, 138 int clipTop, 139 int clipRight, 140 int clipBottom, 141 float[] transform, 142 int renderMode, 143 int showAnnotTypes, 144 boolean renderFormFields); 145 146 /** 147 * Clones the currently loaded document using the provided file descriptor. 148 * <p>You are required to detach the file descriptor as the native code will close it. 149 * 150 * @param destination native fd pointer 151 * @return true if the cloning was successful 152 */ cloneWithoutSecurity(int destination)153 private native boolean cloneWithoutSecurity(int destination); 154 155 /** 156 * Clones the currently loaded document using the provided file descriptor. 157 * <p>You are required to detach the file descriptor as the native code will close it. 158 * 159 * @param destination {@link ParcelFileDescriptor} to which the document needs to be written to. 160 * @return true if the cloning was successful 161 */ cloneWithoutSecurity(ParcelFileDescriptor destination)162 public boolean cloneWithoutSecurity(ParcelFileDescriptor destination) { 163 return cloneWithoutSecurity(destination.detachFd()); 164 } 165 166 /** 167 * Gets the text of the entire page as a string, in the order the text is 168 * found in the PDF stream. 169 */ getPageText(int pageNum)170 public native String getPageText(int pageNum); 171 172 /** 173 * Gets all pieces of alt-text found for the page, in the order the alt-text is found in the 174 * PDF stream. 175 */ getPageAltText(int pageNum)176 public native List<String> getPageAltText(int pageNum); 177 178 /** 179 * Searches for the given string on the page and returns the bounds of all of the matches. 180 * The number of matches is {@link MatchRects#size()}. 181 */ searchPageText(int pageNum, String query)182 public native MatchRects searchPageText(int pageNum, String query); 183 184 /** 185 * Get the text selection that spans between the two boundaries (inclusive of start and 186 * exclusive of stop), both of which can be either exactly defined with text indexes, or 187 * approximately defined with points on the page. The resulting selection will also be exactly 188 * defined with both indexes and points. If the start and stop boundary are both the same point, 189 * selects the word at that point. 190 */ selectPageText(int pageNum, SelectionBoundary start, SelectionBoundary stop)191 public native PageSelection selectPageText(int pageNum, SelectionBoundary start, 192 SelectionBoundary stop); 193 194 /** Get the bounds and URLs of all the links on the given page. */ getPageLinks(int pageNum)195 public native LinkRects getPageLinks(int pageNum); 196 197 /** Returns bookmarks and other goto links (within the current document) on a page */ getPageGotoLinks(int pageNum)198 public native List<PdfPageGotoLinkContent> getPageGotoLinks(int pageNum); 199 200 /** Loads a page object and retains it in memory when a page becomes visible. */ retainPage(int pageNum)201 public native void retainPage(int pageNum); 202 203 /** Cleans up objects in memory related to a page after it is no longer visible. */ releasePage(int pageNum)204 public native void releasePage(int pageNum); 205 206 /** Returns true if the PDF is linearized. (May give false negatives for <1KB PDFs). */ isPdfLinearized()207 public native boolean isPdfLinearized(); 208 209 /** Returns true if the document prefers to be scaled for printing. */ scaleForPrinting()210 public native boolean scaleForPrinting(); 211 212 /** 213 * Returns an int representing the form type contained in the PDF, e.g. Acro vs XFA (if any). 214 */ getFormType()215 public native int getFormType(); 216 217 /** Obtains information about the widget at point ({@code x}, {@code y}), if any. */ getFormWidgetInfo(int pageNum, int x, int y)218 public native FormWidgetInfo getFormWidgetInfo(int pageNum, int x, int y); 219 220 /** 221 * Obtains information about the widget with ({@code annotationIndex} on page {@code pageNum}), 222 * if any. 223 */ getFormWidgetInfo(int pageNum, int annotationIndex)224 public native FormWidgetInfo getFormWidgetInfo(int pageNum, int annotationIndex); 225 226 /** 227 * Obtains information about all form widgets on page ({@code pageNum}, if any. 228 * 229 * <p>Optionally restricts by {@code typeIds}. If {@code typeIds} is empty, all form widgets on 230 * the page will be returned. 231 */ getFormWidgetInfos(int pageNum, int[] typeIds)232 public native List<FormWidgetInfo> getFormWidgetInfos(int pageNum, int[] typeIds); 233 234 /** 235 * Executes an interactive click on the page at the given point ({@code x}, {@code y}). 236 * 237 * @return rectangular areas of the page bitmap that have been invalidated by this action 238 */ clickOnPage(int pageNum, int x, int y)239 public native List<Rect> clickOnPage(int pageNum, int x, int y); 240 241 /** 242 * Sets the text of the widget at {@code annotationIndex}, if applicable. 243 * 244 * @return rectangular areas of the page bitmap that have been invalidated by this action 245 */ setFormFieldText(int pageNum, int annotIndex, String text)246 public native List<Rect> setFormFieldText(int pageNum, int annotIndex, String text); 247 248 /** 249 * Selects the {@code selectedIndices} and unselects all others for the widget at {@code 250 * annotationIndex}, if applicable. 251 * 252 * @return Rectangular areas of the page bitmap that have been invalidated by this action 253 */ setFormFieldSelectedIndices( int pageNum, int annotIndex, int[] selectedIndices)254 public native List<Rect> setFormFieldSelectedIndices( 255 int pageNum, int annotIndex, int[] selectedIndices); 256 } 257