diff options
5 files changed, 491 insertions, 17 deletions
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp index 5f60c9e..2b756e2 100644 --- a/core/jni/android/graphics/pdf/PdfEditor.cpp +++ b/core/jni/android/graphics/pdf/PdfEditor.cpp @@ -19,6 +19,9 @@ #include "fpdfview.h" #include "fpdfedit.h" #include "fpdfsave.h" +#include "fsdk_rendercontext.h" +#include "fpdf_transformpage.h" +#include "SkMatrix.h" #include <android_runtime/AndroidRuntime.h> #include <vector> @@ -29,6 +32,20 @@ namespace android { +enum PageBox {PAGE_BOX_MEDIA, PAGE_BOX_CROP}; + +static struct { + jfieldID x; + jfieldID y; +} gPointClassInfo; + +static struct { + jfieldID left; + jfieldID top; + jfieldID right; + jfieldID bottom; +} gRectClassInfo; + static Mutex sLock; static int sUnmatchedInitRequestCount = 0; @@ -144,18 +161,201 @@ static void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) { } } +static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, + jlong transformPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom) { + FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); + + CPDF_Page* page = (CPDF_Page*) FPDF_LoadPage(document, pageIndex); + if (!page) { + jniThrowException(env, "java/lang/IllegalStateException", + "cannot open page"); + return; + } + + double width = 0; + double height = 0; + + const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height); + if (!result) { + jniThrowException(env, "java/lang/IllegalStateException", + "cannot get page size"); + return; + } + + CFX_AffineMatrix matrix; + + SkMatrix* skTransform = reinterpret_cast<SkMatrix*>(transformPtr); + + SkScalar transformValues[6]; + skTransform->asAffine(transformValues); + + // PDF's coordinate system origin is left-bottom while in graphics it + // is the top-left. So, translate the PDF coordinates to ours. + matrix.Set(1, 0, 0, -1, 0, page->GetPageHeight()); + + // Apply the transformation what was created in our coordinates. + matrix.Concat(transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY], + transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY], + transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]); + + // Translate the result back to PDF coordinates. + matrix.Concat(1, 0, 0, -1, 0, page->GetPageHeight()); + + FS_MATRIX transform = {matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f}; + FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom}; + + FPDFPage_TransFormWithClip(page, &transform, &clip); + + FPDF_ClosePage(page); +} + +static void nativeGetPageSize(JNIEnv* env, jclass thiz, jlong documentPtr, + jint pageIndex, jobject outSize) { + FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); + + FPDF_PAGE page = FPDF_LoadPage(document, pageIndex); + if (!page) { + jniThrowException(env, "java/lang/IllegalStateException", + "cannot open page"); + return; + } + + double width = 0; + double height = 0; + + const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height); + if (!result) { + jniThrowException(env, "java/lang/IllegalStateException", + "cannot get page size"); + return; + } + + env->SetIntField(outSize, gPointClassInfo.x, width); + env->SetIntField(outSize, gPointClassInfo.y, height); + + FPDF_ClosePage(page); +} + +static jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) { + FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); + FPDF_BOOL success = FPDF_VIEWERREF_GetPrintScaling(document); + return success ? JNI_TRUE : JNI_FALSE; +} + +static bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, + PageBox pageBox, jobject outBox) { + FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); + + FPDF_PAGE page = FPDF_LoadPage(document, pageIndex); + if (!page) { + jniThrowException(env, "java/lang/IllegalStateException", + "cannot open page"); + return false; + } + + float left; + float top; + float right; + float bottom; + + const FPDF_BOOL success = (pageBox == PAGE_BOX_MEDIA) + ? FPDFPage_GetMediaBox(page, &left, &top, &right, &bottom) + : FPDFPage_GetCropBox(page, &left, &top, &right, &bottom); + + FPDF_ClosePage(page); + + if (!success) { + return false; + } + + env->SetIntField(outBox, gRectClassInfo.left, (int) left); + env->SetIntField(outBox, gRectClassInfo.top, (int) top); + env->SetIntField(outBox, gRectClassInfo.right, (int) right); + env->SetIntField(outBox, gRectClassInfo.bottom, (int) bottom); + + return true; +} + +static jboolean nativeGetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, + jobject outMediaBox) { + const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA, + outMediaBox); + return success ? JNI_TRUE : JNI_FALSE; +} + +static jboolean nativeGetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, + jobject outMediaBox) { + const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, + outMediaBox); + return success ? JNI_TRUE : JNI_FALSE; +} + +static void nativeSetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, + PageBox pageBox, jobject box) { + FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); + + FPDF_PAGE page = FPDF_LoadPage(document, pageIndex); + if (!page) { + jniThrowException(env, "java/lang/IllegalStateException", + "cannot open page"); + return; + } + + const int left = env->GetIntField(box, gRectClassInfo.left); + const int top = env->GetIntField(box, gRectClassInfo.top); + const int right = env->GetIntField(box, gRectClassInfo.right); + const int bottom = env->GetIntField(box, gRectClassInfo.bottom); + + if (pageBox == PAGE_BOX_MEDIA) { + FPDFPage_SetMediaBox(page, left, top, right, bottom); + } else { + FPDFPage_SetCropBox(page, left, top, right, bottom); + } + + FPDF_ClosePage(page); +} + +static void nativeSetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, + jobject mediaBox) { + nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA, mediaBox); +} + +static void nativeSetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, + jobject mediaBox) { + nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox); +} + static JNINativeMethod gPdfEditor_Methods[] = { {"nativeOpen", "(IJ)J", (void*) nativeOpen}, {"nativeClose", "(J)V", (void*) nativeClose}, {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount}, {"nativeRemovePage", "(JI)I", (void*) nativeRemovePage}, - {"nativeWrite", "(JI)V", (void*) nativeWrite} + {"nativeWrite", "(JI)V", (void*) nativeWrite}, + {"nativeSetTransformAndClip", "(JIJIIII)V", (void*) nativeSetTransformAndClip}, + {"nativeGetPageSize", "(JILandroid/graphics/Point;)V", (void*) nativeGetPageSize}, + {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting}, + {"nativeGetPageMediaBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageMediaBox}, + {"nativeSetPageMediaBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageMediaBox}, + {"nativeGetPageCropBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageCropBox}, + {"nativeSetPageCropBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageCropBox} }; int register_android_graphics_pdf_PdfEditor(JNIEnv* env) { - return android::AndroidRuntime::registerNativeMethods( + const int result = android::AndroidRuntime::registerNativeMethods( env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods, NELEM(gPdfEditor_Methods)); + + jclass pointClass = env->FindClass("android/graphics/Point"); + gPointClassInfo.x = env->GetFieldID(pointClass, "x", "I"); + gPointClassInfo.y = env->GetFieldID(pointClass, "y", "I"); + + jclass rectClass = env->FindClass("android/graphics/Rect"); + gRectClassInfo.left = env->GetFieldID(rectClass, "left", "I"); + gRectClassInfo.top = env->GetFieldID(rectClass, "top", "I"); + gRectClassInfo.right = env->GetFieldID(rectClass, "right", "I"); + gRectClassInfo.bottom = env->GetFieldID(rectClass, "bottom", "I"); + + return result; }; }; diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java index 9837139..0b84d29 100644 --- a/graphics/java/android/graphics/pdf/PdfEditor.java +++ b/graphics/java/android/graphics/pdf/PdfEditor.java @@ -17,6 +17,10 @@ package android.graphics.pdf; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.graphics.Matrix; +import android.graphics.Point; +import android.graphics.Rect; import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import android.system.OsConstants; @@ -98,6 +102,109 @@ public final class PdfEditor { } /** + * Sets a transformation and clip for a given page. The transformation matrix if + * non-null must be affine as per {@link android.graphics.Matrix#isAffine()}. If + * the clip is null, then no clipping is performed. + * + * @param pageIndex The page whose transform to set. + * @param transform The transformation to apply. + * @param clip The clip to apply. + */ + public void setTransformAndClip(int pageIndex, @Nullable Matrix transform, + @Nullable Rect clip) { + throwIfClosed(); + throwIfPageNotInDocument(pageIndex); + throwIfNotNullAndNotAfine(transform); + if (transform == null) { + transform = Matrix.IDENTITY_MATRIX; + } + if (clip == null) { + Point size = new Point(); + getPageSize(pageIndex, size); + nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance, + 0, 0, size.x, size.y); + } else { + nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance, + clip.left, clip.top, clip.right, clip.bottom); + } + } + + /** + * Gets the size of a given page in mils (1/72"). + * + * @param pageIndex The page index. + * @param outSize The size output. + */ + public void getPageSize(int pageIndex, @NonNull Point outSize) { + throwIfClosed(); + throwIfOutSizeNull(outSize); + throwIfPageNotInDocument(pageIndex); + nativeGetPageSize(mNativeDocument, pageIndex, outSize); + } + + /** + * Gets the media box of a given page in mils (1/72"). + * + * @param pageIndex The page index. + * @param outMediaBox The media box output. + */ + public boolean getPageMediaBox(int pageIndex, @NonNull Rect outMediaBox) { + throwIfClosed(); + throwIfOutMediaBoxNull(outMediaBox); + throwIfPageNotInDocument(pageIndex); + return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox); + } + + /** + * Sets the media box of a given page in mils (1/72"). + * + * @param pageIndex The page index. + * @param mediaBox The media box. + */ + public void setPageMediaBox(int pageIndex, @NonNull Rect mediaBox) { + throwIfClosed(); + throwIfMediaBoxNull(mediaBox); + throwIfPageNotInDocument(pageIndex); + nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox); + } + + /** + * Gets the crop box of a given page in mils (1/72"). + * + * @param pageIndex The page index. + * @param outCropBox The crop box output. + */ + public boolean getPageCropBox(int pageIndex, @NonNull Rect outCropBox) { + throwIfClosed(); + throwIfOutCropBoxNull(outCropBox); + throwIfPageNotInDocument(pageIndex); + return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox); + } + + /** + * Sets the crop box of a given page in mils (1/72"). + * + * @param pageIndex The page index. + * @param cropBox The crop box. + */ + public void setPageCropBox(int pageIndex, @NonNull Rect cropBox) { + throwIfClosed(); + throwIfCropBoxNull(cropBox); + throwIfPageNotInDocument(pageIndex); + nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox); + } + + /** + * Gets whether the document prefers to be scaled for printing. + * + * @return Whether to scale the document. + */ + public boolean shouldScaleForPrinting() { + throwIfClosed(); + return nativeScaleForPrinting(mNativeDocument); + } + + /** * Writes the PDF file to the provided destination. * <p> * <strong>Note:</strong> This method takes ownership of the passed in file @@ -154,9 +261,57 @@ public final class PdfEditor { } } + private void throwIfNotNullAndNotAfine(Matrix matrix) { + if (matrix != null && !matrix.isAffine()) { + throw new IllegalStateException("Matrix must be afine"); + } + } + + private void throwIfOutSizeNull(Point outSize) { + if (outSize == null) { + throw new NullPointerException("outSize cannot be null"); + } + } + + private void throwIfOutMediaBoxNull(Rect outMediaBox) { + if (outMediaBox == null) { + throw new NullPointerException("outMediaBox cannot be null"); + } + } + + private void throwIfMediaBoxNull(Rect mediaBox) { + if (mediaBox == null) { + throw new NullPointerException("mediaBox cannot be null"); + } + } + + private void throwIfOutCropBoxNull(Rect outCropBox) { + if (outCropBox == null) { + throw new NullPointerException("outCropBox cannot be null"); + } + } + + private void throwIfCropBoxNull(Rect cropBox) { + if (cropBox == null) { + throw new NullPointerException("cropBox cannot be null"); + } + } + private static native long nativeOpen(int fd, long size); private static native void nativeClose(long documentPtr); private static native int nativeGetPageCount(long documentPtr); private static native int nativeRemovePage(long documentPtr, int pageIndex); private static native void nativeWrite(long documentPtr, int fd); + private static native void nativeSetTransformAndClip(long documentPtr, int pageIndex, + long transformPtr, int clipLeft, int clipTop, int clipRight, int clipBottom); + private static native void nativeGetPageSize(long documentPtr, int pageIndex, Point outSize); + private static native boolean nativeGetPageMediaBox(long documentPtr, int pageIndex, + Rect outMediaBox); + private static native void nativeSetPageMediaBox(long documentPtr, int pageIndex, + Rect mediaBox); + private static native boolean nativeGetPageCropBox(long documentPtr, int pageIndex, + Rect outMediaBox); + private static native void nativeSetPageCropBox(long documentPtr, int pageIndex, + Rect mediaBox); + private static native boolean nativeScaleForPrinting(long documentPtr); } diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl index b450ccb..01cabe1 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl +++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl @@ -18,6 +18,7 @@ package com.android.printspooler.renderer; import android.os.ParcelFileDescriptor; import android.print.PageRange; +import android.print.PrintAttributes; /** * Interface for communication with a remote pdf editor. @@ -25,6 +26,7 @@ import android.print.PageRange; interface IPdfEditor { int openDocument(in ParcelFileDescriptor source); void removePages(in PageRange[] pages); + void applyPrintAttributes(in PrintAttributes attributes); void write(in ParcelFileDescriptor destination); void closeDocument(); } diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java index 00e5051..0462e4d 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java @@ -87,7 +87,7 @@ public final class PdfManipulationService extends Service { } mRenderer = new PdfRenderer(source); return mRenderer.getPageCount(); - } catch (IOException|IllegalStateException e) { + } catch (IOException | IllegalStateException e) { IoUtils.closeQuietly(source); Log.e(LOG_TAG, "Cannot open file", e); return MALFORMED_PDF_FILE_ERROR; @@ -217,7 +217,7 @@ public final class PdfManipulationService extends Service { } mEditor = new PdfEditor(source); return mEditor.getPageCount(); - } catch (IOException|IllegalStateException e) { + } catch (IOException | IllegalStateException e) { IoUtils.closeQuietly(source); Log.e(LOG_TAG, "Cannot open file", e); throw new RemoteException(e.toString()); @@ -246,6 +246,111 @@ public final class PdfManipulationService extends Service { } @Override + public void applyPrintAttributes(PrintAttributes attributes) { + synchronized (mLock) { + throwIfNotOpened(); + if (DEBUG) { + Log.i(LOG_TAG, "applyPrintAttributes()"); + } + + Rect mediaBox = new Rect(); + Rect cropBox = new Rect(); + Matrix transform = new Matrix(); + + final boolean contentPortrait = attributes.getMediaSize().isPortrait(); + + final boolean layoutDirectionRtl = getResources().getConfiguration() + .getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + + // We do not want to rotate the media box, so take into account orientation. + final int dstWidthPts = contentPortrait + ? pointsFromMils(attributes.getMediaSize().getWidthMils()) + : pointsFromMils(attributes.getMediaSize().getHeightMils()); + final int dstHeightPts = contentPortrait + ? pointsFromMils(attributes.getMediaSize().getHeightMils()) + : pointsFromMils(attributes.getMediaSize().getWidthMils()); + + final boolean scaleForPrinting = mEditor.shouldScaleForPrinting(); + + final int pageCount = mEditor.getPageCount(); + for (int i = 0; i < pageCount; i++) { + if (!mEditor.getPageMediaBox(i, mediaBox)) { + Log.e(LOG_TAG, "Malformed PDF file"); + return; + } + + final int srcWidthPts = mediaBox.width(); + final int srcHeightPts = mediaBox.height(); + + // Update the media box with the desired size. + mediaBox.right = dstWidthPts; + mediaBox.bottom = dstHeightPts; + mEditor.setPageMediaBox(i, mediaBox); + + // Make sure content is top-left after media box resize. + transform.setTranslate(0, srcHeightPts - dstHeightPts); + + // Rotate the content if in landscape. + if (!contentPortrait) { + transform.postRotate(270); + transform.postTranslate(0, dstHeightPts); + } + + // Scale the content if document allows it. + final float scale; + if (scaleForPrinting) { + if (contentPortrait) { + scale = Math.min((float) dstWidthPts / srcWidthPts, + (float) dstHeightPts / srcHeightPts); + transform.postScale(scale, scale); + } else { + scale = Math.min((float) dstWidthPts / srcHeightPts, + (float) dstHeightPts / srcWidthPts); + transform.postScale(scale, scale, mediaBox.left, mediaBox.bottom); + } + } else { + scale = 1.0f; + } + + // Update the crop box relatively to the media box change, if needed. + if (mEditor.getPageCropBox(i, cropBox)) { + cropBox.left = (int) (cropBox.left * scale + 0.5f); + cropBox.top = (int) (cropBox.top * scale + 0.5f); + cropBox.right = (int) (cropBox.right * scale + 0.5f); + cropBox.bottom = (int) (cropBox.bottom * scale + 0.5f); + cropBox.intersect(mediaBox); + mEditor.setPageCropBox(i, cropBox); + } + + // If in RTL mode put the content in the logical top-right corner. + if (layoutDirectionRtl) { + final float dx = contentPortrait + ? dstWidthPts - (int) (srcWidthPts * scale + 0.5f) : 0; + final float dy = contentPortrait + ? 0 : - (dstHeightPts - (int) (srcWidthPts * scale + 0.5f)); + transform.postTranslate(dx, dy); + } + + // Adjust the physical margins if needed. + Margins minMargins = attributes.getMinMargins(); + final int paddingLeftPts = pointsFromMils(minMargins.getLeftMils()); + final int paddingTopPts = pointsFromMils(minMargins.getTopMils()); + final int paddingRightPts = pointsFromMils(minMargins.getRightMils()); + final int paddingBottomPts = pointsFromMils(minMargins.getBottomMils()); + + Rect clip = new Rect(mediaBox); + clip.left += paddingLeftPts; + clip.top += paddingTopPts; + clip.right -= paddingRightPts; + clip.bottom -= paddingBottomPts; + + // Apply the accumulated transforms. + mEditor.setTransformAndClip(i, transform, clip); + } + } + } + + @Override public void write(ParcelFileDescriptor destination) throws RemoteException { synchronized (mLock) { try { diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java index 15ea9a7..f361884 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java @@ -592,7 +592,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat mDestinationSpinner.post(new Runnable() { @Override public void run() { - shredPagesAndFinish(uri); + transformDocumentAndFinish(uri); } }); } else if (resultCode == RESULT_CANCELED) { @@ -922,7 +922,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat if (mCurrentPrinter == mDestinationSpinnerAdapter.getPdfPrinter()) { startCreateDocumentActivity(); } else { - shredPagesAndFinish(null); + transformDocumentAndFinish(null); } } @@ -1597,8 +1597,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat return true; } - private void shredPagesAndFinish(final Uri writeToUri) { - new PageShredder(this, mPrintJob, mFileProvider, new Runnable() { + private void transformDocumentAndFinish(final Uri writeToUri) { + // If saving to PDF, apply the attibutes as we are acting as a print service. + PrintAttributes attributes = mDestinationSpinnerAdapter.getPdfPrinter() == mCurrentPrinter + ? mPrintJob.getAttributes() : null; + new DocumentTransformer(this, mPrintJob, mFileProvider, attributes, new Runnable() { @Override public void run() { if (writeToUri != null) { @@ -1606,7 +1609,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } doFinish(); } - }).shred(); + }).transform(); } private void doFinish() { @@ -2329,7 +2332,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } } - private static final class PageShredder implements ServiceConnection { + private static final class DocumentTransformer implements ServiceConnection { private static final String TEMP_FILE_PREFIX = "print_job"; private static final String TEMP_FILE_EXTENSION = ".pdf"; @@ -2341,20 +2344,24 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat private final PageRange[] mPagesToShred; + private final PrintAttributes mAttributesToApply; + private final Runnable mCallback; - public PageShredder(Context context, PrintJobInfo printJob, - MutexFileProvider fileProvider, Runnable callback) { + public DocumentTransformer(Context context, PrintJobInfo printJob, + MutexFileProvider fileProvider, PrintAttributes attributes, + Runnable callback) { mContext = context; mPrintJob = printJob; mFileProvider = fileProvider; mCallback = callback; mPagesToShred = computePagesToShred(mPrintJob); + mAttributesToApply = attributes; } - public void shred() { + public void transform() { // If we have only the pages we want, done. - if (mPagesToShred.length <= 0) { + if (mPagesToShred.length <= 0 && mAttributesToApply == null) { mCallback.run(); return; } @@ -2376,14 +2383,14 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat // final and this code is the last one to touch // them as shredding is the very last step, so the // UI is not interactive at this point. - shredPages(editor); + doTransform(editor); updatePrintJob(); return null; } @Override protected void onPostExecute(Void aVoid) { - mContext.unbindService(PageShredder.this); + mContext.unbindService(DocumentTransformer.this); mCallback.run(); } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -2394,7 +2401,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat /* do nothing */ } - private void shredPages(IPdfEditor editor) { + private void doTransform(IPdfEditor editor) { File tempFile = null; ParcelFileDescriptor src = null; ParcelFileDescriptor dst = null; @@ -2413,6 +2420,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat // Drop the pages. editor.removePages(mPagesToShred); + // Apply print attributes if needed. + if (mAttributesToApply != null) { + editor.applyPrintAttributes(mAttributesToApply); + } + // Write the modified PDF to a temp file. tempFile = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_EXTENSION, mContext.getCacheDir()); |