MTK图片处理的工具类

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.Math;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.media.ExifInterface;
import android.util.Log;

import com.android.videoeditor.R;
import com.android.videoeditor.service.MovieOverlay;

/**
 * Image utility methods
 */
public class ImageUtils {
    /**
     *  Logging
     */
    private static final String TAG = "ImageUtils";

    // The resize paint
    private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);

    // The match aspect ratio mode for scaleImage
    public static int MATCH_SMALLER_DIMENSION = 1;
    public static int MATCH_LARGER_DIMENSION = 2;

    /**
     * It is not possible to instantiate this class
     */
    private ImageUtils() {
    }

    /**
     * Resize a bitmap to the specified width and height.
     *
     * @param filename The filename
     * @param width The thumbnail width
     * @param height The thumbnail height
     * @param match MATCH_SMALLER_DIMENSION or MATCH_LARGER_DIMMENSION
     *
     * @return The resized bitmap
     */
    public static Bitmap scaleImage(String filename, int width, int height, int match)
            throws IOException {
        final BitmapFactory.Options dbo = new BitmapFactory.Options();
        dbo.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filename, dbo);

        final int nativeWidth = dbo.outWidth;
        final int nativeHeight = dbo.outHeight;

        final Bitmap srcBitmap;
        float scaledWidth, scaledHeight;
        final BitmapFactory.Options options = new BitmapFactory.Options();
        if (nativeWidth > width || nativeHeight > height) {
            float dx = ((float) nativeWidth) / ((float) width);
            float dy = ((float) nativeHeight) / ((float) height);
            float scale = (match == MATCH_SMALLER_DIMENSION) ? Math.max(dx,dy) : Math.min(dx,dy);
            scaledWidth = nativeWidth / scale;
            scaledHeight = nativeHeight / scale;
            // Create the bitmap from file.
            options.inSampleSize = (scale > 1.0f) ? ((int) scale) : 1;
       } else {
            scaledWidth = width;
            scaledHeight = height;
            options.inSampleSize = 1;
       }

       srcBitmap = BitmapFactory.decodeFile(filename, options);
       if (srcBitmap == null) {
         throw new IOException("Cannot decode file: " + filename);
       }

       // Create the canvas bitmap.
       final Bitmap bitmap = Bitmap.createBitmap(Math.round(scaledWidth),
               Math.round(scaledHeight),
               Bitmap.Config.ARGB_8888);
       final Canvas canvas = new Canvas(bitmap);
       canvas.drawBitmap(srcBitmap,
               new Rect(0, 0, srcBitmap.getWidth(), srcBitmap.getHeight()),
               new Rect(0, 0, Math.round(scaledWidth), Math.round(scaledHeight)),
               sResizePaint);

       // Release the source bitmap
       srcBitmap.recycle();
       return bitmap;
    }

    /**
     * Rotate a JPEG according to the EXIF data
     *
     * @param inputFilename The name of the input file (must be a JPEG filename)
     * @param outputFile The rotated file
     *
     * @return true if the image was rotated
     */
    public static boolean transformJpeg(String inputFilename, File outputFile)
            throws IOException {
        final ExifInterface exif = new ExifInterface(inputFilename);
        final int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_UNDEFINED);

        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Exif orientation: " + orientation);
        }

        // Degrees by which we rotate the image.
        int degrees = 0;
        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90: {
                degrees = 90;
                break;
            }

            case ExifInterface.ORIENTATION_ROTATE_180: {
                degrees = 180;
                break;
            }

            case ExifInterface.ORIENTATION_ROTATE_270: {
                degrees = 270;
                break;
            }
        }
        rotateAndScaleImage(inputFilename, degrees, outputFile);
        return degrees != 0;
    }

    /**
     * Rotates an image according to the specified {@code orientation}.
     * We limit the number of pixels of the scaled image. Thus the image
     * will typically be downsampled.
     *
     * @param inputFilename The input filename
     * @param orientation The rotation angle
     * @param outputFile The output file
     */
    private static void rotateAndScaleImage(String inputFilename, int orientation, File outputFile)
            throws FileNotFoundException, IOException {
        // In order to avoid OutOfMemoryError when rotating the image, we scale down the size of the
        // input image. We set the maxmimum number of allowed pixels to 2M and scale down the image
        // accordingly.

        // Determine width and height of the original bitmap without allocating memory for it,
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(inputFilename, opt);

        // Determine the scale factor based on the ratio of pixel count over max allowed pixels.
        final int width = opt.outWidth;
        final int height = opt.outHeight;
        final int pixelCount = width * height;
        final int MAX_PIXELS_FOR_SCALED_IMAGE = 2000000;
        double scale = Math.sqrt( (double) pixelCount / MAX_PIXELS_FOR_SCALED_IMAGE);
        if (scale <= 1) {
          scale = 1;
        } else {
          // Make the scale factor a power of 2 for faster processing. Also the resulting bitmap may
          // have different dimensions than what has been requested if the scale factor is not a
          // power of 2.
          scale = nextPowerOf2((int) Math.ceil(scale));
        }

        // Load the scaled image.
        BitmapFactory.Options opt2 = new BitmapFactory.Options();
        opt2.inSampleSize = (int) scale;
        final Bitmap scaledBmp = BitmapFactory.decodeFile(inputFilename, opt2);

        // Rotation matrix used to rotate the image.
        final Matrix mtx = new Matrix();
        mtx.postRotate(orientation);

        final Bitmap rotatedBmp = Bitmap.createBitmap(scaledBmp, 0, 0,
                scaledBmp.getWidth(), scaledBmp.getHeight(), mtx, true);
        if (rotatedBmp != scaledBmp) scaledBmp.recycle();

        // Save the rotated image to a file in the current project folder
        final FileOutputStream fos = new FileOutputStream(outputFile);
        rotatedBmp.compress(CompressFormat.JPEG, 100, fos);
        fos.close();

        rotatedBmp.recycle();
    }

    /**
     * Returns the next power of two.
     * Returns the input if it is already power of 2.
     * Throws IllegalArgumentException if the input is <= 0 or the answer overflows.
     */
    private static int nextPowerOf2(int n) {
        if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException();
        n -= 1;
        n |= n >> 16;
        n |= n >> 8;
        n |= n >> 4;
        n |= n >> 2;
        n |= n >> 1;
        return n + 1;
    }

    /**
     * Build an overlay image
     *
     * @param context The context
     * @param inputBitmap If the bitmap is provided no not create a new one
     * @param overlayType The overlay type
     * @param title The title
     * @param subTitle The subtitle
     * @param width The width
     * @param height The height
     *
     * @return The bitmap
     */
    public static Bitmap buildOverlayBitmap(Context context, Bitmap inputBitmap, int overlayType,
            String title, String subTitle, int width, int height) {
        final Bitmap overlayBitmap;
        if (inputBitmap == null) {
            overlayBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        } else {
            overlayBitmap = inputBitmap;
        }

        overlayBitmap.eraseColor(Color.TRANSPARENT);
        final Canvas canvas = new Canvas(overlayBitmap);

        switch (overlayType) {
            case MovieOverlay.OVERLAY_TYPE_CENTER_1: {
                drawCenterOverlay(context, canvas, R.drawable.overlay_background_1,
                        Color.WHITE, title, subTitle, width, height);
                break;
            }

            case MovieOverlay.OVERLAY_TYPE_BOTTOM_1: {
                drawBottomOverlay(context, canvas, R.drawable.overlay_background_1,
                        Color.WHITE, title, subTitle, width, height);
                break;
            }

            case MovieOverlay.OVERLAY_TYPE_CENTER_2: {
                drawCenterOverlay(context, canvas, R.drawable.overlay_background_2,
                        Color.BLACK, title, subTitle, width, height);
                break;
            }

            case MovieOverlay.OVERLAY_TYPE_BOTTOM_2: {
                drawBottomOverlay(context, canvas, R.drawable.overlay_background_2,
                        Color.BLACK, title, subTitle, width, height);
                break;
            }

            default: {
                throw new IllegalArgumentException("Unsupported overlay type: " + overlayType);
            }
        }

        return overlayBitmap;
    }

    /**
     * Build an overlay image in the center third of the image
     *
     * @param context The context
     * @param canvas The canvas
     * @param drawableId The overlay background drawable if
     * @param textColor The text color
     * @param title The title
     * @param subTitle The subtitle
     * @param width The width
     * @param height The height
     */
    private static void drawCenterOverlay(Context context, Canvas canvas, int drawableId,
            int textColor, String title, String subTitle, int width, int height) {
        final int INSET = width / 72;
        final int startHeight = (height / 3) + INSET;
        final Drawable background = context.getResources().getDrawable(drawableId);
        background.setBounds(INSET, startHeight, width - INSET,
                ((2 * height) / 3) - INSET);
        background.draw(canvas);

        final Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        p.setTypeface(Typeface.DEFAULT_BOLD);
        p.setColor(textColor);

        final int titleFontSize = height / 12;
        final int maxWidth = width - (2 * INSET) - (2 * titleFontSize);
        final int startYOffset = startHeight + (height / 6);
        if (title != null) {
            p.setTextSize(titleFontSize);
            title = StringUtils.trimText(title, p, maxWidth);
            canvas.drawText(title, (width - (2 * INSET) - p.measureText(title)) / 2,
                    startYOffset - p.descent(), p);
        }

        if (subTitle != null) {
            p.setTextSize(titleFontSize - 6);
            subTitle = StringUtils.trimText(subTitle, p, maxWidth);
            canvas.drawText(subTitle, (width - (2 * INSET) - p.measureText(subTitle)) / 2,
                    startYOffset - p.ascent(), p);
        }
    }

    /**
     * Build an overlay image in the lower third of the image
     *
     * @param context The context
     * @param canvas The canvas
     * @param drawableId The overlay background drawable if
     * @param textColor The text color
     * @param title The title
     * @param subTitle The subtitle
     * @param width The width
     * @param height The height
     */
    private static void drawBottomOverlay(Context context, Canvas canvas, int drawableId,
            int textColor, String title, String subTitle, int width, int height) {
        final int INSET = width / 72;
        final int startHeight = ((2 * height) / 3) + INSET;
        final Drawable background = context.getResources().getDrawable(drawableId);
        background.setBounds(INSET, startHeight, width - INSET, height - INSET);
        background.draw(canvas);

        final Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        p.setTypeface(Typeface.DEFAULT_BOLD);
        p.setColor(textColor);

        final int titleFontSize = height / 12;
        final int maxWidth = width - (2 * INSET) - (2 * titleFontSize);
        final int startYOffset = startHeight + (height / 6);
        if (title != null) {
            p.setTextSize(titleFontSize);
            title = StringUtils.trimText(title, p, maxWidth);
            canvas.drawText(title, (width - (2 * INSET) - p.measureText(title)) / 2,
                    startYOffset - p.descent(), p);
        }

        if (subTitle != null) {
            p.setTextSize(titleFontSize - 6);
            subTitle = StringUtils.trimText(subTitle, p, maxWidth);
            canvas.drawText(subTitle, (width - (2 * INSET) - p.measureText(subTitle)) / 2,
                    startYOffset - p.ascent(), p);
        }
    }

    /**
     * Build an overlay preview image
     *
     * @param context The context
     * @param canvas The canvas
     * @param overlayType The overlay type
     * @param title The title
     * @param subTitle The subtitle
     * @param startX The start horizontal position
     * @param startY The start vertical position
     * @param width The width
     * @param height The height
     */
    public static void buildOverlayPreview(Context context, Canvas canvas, int overlayType,
            String title, String subTitle, int startX, int startY, int width, int height) {
        switch (overlayType) {
            case MovieOverlay.OVERLAY_TYPE_CENTER_1:
            case MovieOverlay.OVERLAY_TYPE_BOTTOM_1: {
                drawOverlayPreview(context, canvas, R.drawable.overlay_background_1,
                        Color.WHITE, title, subTitle, startX, startY, width, height);
                break;
            }

            case MovieOverlay.OVERLAY_TYPE_CENTER_2:
            case MovieOverlay.OVERLAY_TYPE_BOTTOM_2: {
                drawOverlayPreview(context, canvas, R.drawable.overlay_background_2,
                        Color.BLACK, title, subTitle, startX, startY, width, height);
                break;
            }

            default: {
                throw new IllegalArgumentException("Unsupported overlay type: " + overlayType);
            }
        }
    }

    /**
     * Build an overlay image in the lower third of the image
     *
     * @param context The context
     * @param canvas The canvas
     * @param drawableId The overlay background drawable if
     * @param title The title
     * @param subTitle The subtitle
     * @param width The width
     * @param height The height
     */
    private static void drawOverlayPreview(Context context, Canvas canvas, int drawableId,
            int textColor, String title, String subTitle, int startX, int startY, int width,
            int height) {
        final int INSET = 0;
        final int startHeight = startY + INSET;
        final Drawable background = context.getResources().getDrawable(drawableId);
        background.setBounds(startX + INSET, startHeight, startX + width - INSET,
                height - INSET + startY);
        background.draw(canvas);

        final Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        p.setTypeface(Typeface.DEFAULT_BOLD);
        p.setColor(textColor);

        final int titleFontSize = height / 4;
        final int maxWidth = width - (2 * INSET) - (2 * titleFontSize);
        final int startYOffset = startHeight + (height / 2);
        if (title != null) {
            p.setTextSize(titleFontSize);
            title = StringUtils.trimText(title, p, maxWidth);
            canvas.drawText(title, (width - (2 * INSET) - p.measureText(title)) / 2,
                    startYOffset - p.descent(), p);
        }

        if (subTitle != null) {
            p.setTextSize(titleFontSize - 6);
            subTitle = StringUtils.trimText(subTitle, p, maxWidth);
            canvas.drawText(subTitle, (width - (2 * INSET) - p.measureText(subTitle)) / 2,
                    startYOffset - p.ascent(), p);
        }
    }

    private static final boolean LOG = true;
    //please see MediaItemView for more info
    private static final float MAX_ASPECT_RATIO = 18.2F;//18.2 = 2048 * 2048 / 480 / 480
    //generateProjectThumbnail() in VideoEditorImpl and other functions in both java/native layer
    //will occur exception if we import big ratio image.
    public static boolean isPermitedImage(String filename) {
        boolean permited = true;
        float ratio = 0;
        int width = 0, height = 0;
        if (filename != null) {
            BitmapFactory.Options opt = new BitmapFactory.Options();
            opt.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filename, opt);
            width = opt.outWidth;
            height = opt.outHeight;
            if (width < 16 || height < 16) {
                //MDP cannot decode image file size < 4*4, here app set it to 16*16 for FPM's dicision.
                //MediaImageItem will >> 1 << 1, if width or height <= 1, it will be 0.
                permited = false;
            } else {
                ratio = width > height ? ((float)width / height) : ((float)height / width);
                if (ratio > MAX_ASPECT_RATIO) {
                    permited = false;
                }
            }
        }
        if (LOG) MtkLog.v(TAG, "isPermitedRatio(" + filename + ") width=" + width + ", height=" + height
                + ", ratio=" + ratio + ", return " + permited);
        return permited;
    }
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值