Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7389eecb authored by Julian Mancini's avatar Julian Mancini
Browse files

Crop PDF Thumbnails before sending them from Provider

Essentially, if you were to get a PDF Thumbnail for a landscape-oriented
ImageView (more horizontal than vertical), it would just squish the
whole PDF page down. This crops it so it looks nice in landscape and
portrait.

Bug: 63928143
Test: In place
Change-Id: Iaefabba1a96dcee5297bf6639aba8098c9137782
parent 6d423792
Loading
Loading
Loading
Loading
+70 −2
Original line number Diff line number Diff line
@@ -19,8 +19,8 @@ package com.android.internal.content;
import android.annotation.Nullable;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.pdf.PdfRenderer;
import android.os.AsyncTask;
import android.os.ParcelFileDescriptor;
@@ -56,10 +56,13 @@ public final class PdfUtils {
                ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
        PdfRenderer renderer = new PdfRenderer(pdfDescriptor);
        PdfRenderer.Page frontPage = renderer.openPage(0);
        Bitmap thumbnail = Bitmap.createBitmap(size.x, size.y,
        Bitmap thumbnail = Bitmap.createBitmap(frontPage.getWidth(), frontPage.getHeight(),
                Bitmap.Config.ARGB_8888);

        frontPage.render(thumbnail, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);

        thumbnail = crop(thumbnail, size.x, size.y, .5f, 0f);

        // Create an AssetFileDescriptor that contains the Bitmap's information
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        // Quality is an integer that determines how much compression is used.
@@ -93,4 +96,69 @@ public final class PdfUtils {
        return new AssetFileDescriptor(fds[0], 0, AssetFileDescriptor.UNKNOWN_LENGTH);
    }

    /**
     * Returns a new Bitmap copy with a crop effect depending on the crop anchor given. 0.5f is like
     * {@link android.widget.ImageView.ScaleType#CENTER_CROP}. The crop anchor will be be nudged
     * so the entire cropped bitmap will fit inside the src. May return the input bitmap if no
     * scaling is necessary.
     *
     *
     * Example of changing verticalCenterPercent:
     *   _________            _________
     *  |         |          |         |
     *  |         |          |_________|
     *  |         |          |         |/___0.3f
     *  |---------|          |_________|\
     *  |         |<---0.5f  |         |
     *  |---------|          |         |
     *  |         |          |         |
     *  |         |          |         |
     *  |_________|          |_________|
     *
     * @param src original bitmap of any size
     * @param w desired width in px
     * @param h desired height in px
     * @param horizontalCenterPercent determines which part of the src to crop from. Range from 0
     *                                .0f to 1.0f. The value determines which part of the src
     *                                maps to the horizontal center of the resulting bitmap.
     * @param verticalCenterPercent determines which part of the src to crop from. Range from 0
     *                              .0f to 1.0f. The value determines which part of the src maps
     *                              to the vertical center of the resulting bitmap.
     * @return a copy of src conforming to the given width and height, or src itself if it already
     *         matches the given width and height
     *
     */
    private static Bitmap crop(final Bitmap src, final int w, final int h,
            final float horizontalCenterPercent, final float verticalCenterPercent) {
        if (horizontalCenterPercent < 0 || horizontalCenterPercent > 1 || verticalCenterPercent < 0
                || verticalCenterPercent > 1) {
            throw new IllegalArgumentException(
                    "horizontalCenterPercent and verticalCenterPercent must be between 0.0f and "
                            + "1.0f, inclusive.");
        }
        final int srcWidth = src.getWidth();
        final int srcHeight = src.getHeight();
        // exit early if no resize/crop needed
        if (w == srcWidth && h == srcHeight) {
            return src;
        }
        final Matrix m = new Matrix();
        final float scale = Math.max(
                (float) w / srcWidth,
                (float) h / srcHeight);
        m.setScale(scale, scale);
        final int srcCroppedW, srcCroppedH;
        int srcX, srcY;
        srcCroppedW = Math.round(w / scale);
        srcCroppedH = Math.round(h / scale);
        srcX = (int) (srcWidth * horizontalCenterPercent - srcCroppedW / 2);
        srcY = (int) (srcHeight * verticalCenterPercent - srcCroppedH / 2);
        // Nudge srcX and srcY to be within the bounds of src
        srcX = Math.max(Math.min(srcX, srcWidth - srcCroppedW), 0);
        srcY = Math.max(Math.min(srcY, srcHeight - srcCroppedH), 0);
        final Bitmap cropped = Bitmap.createBitmap(src, srcX, srcY,
                srcCroppedW, srcCroppedH, m, true);
        return cropped;
    }

}