Server API 发送图片消息时,缩略图生成逻辑说明

通过 Server API 发送图片消息时,缩略图的生成逻辑可参考本文档生成逻辑说明,文档代码示例中有部 Android 系统接口,有户参考时需要注意替换成自己的实现逻辑,本文只做参考。
发布时间: 2020-04-30 16:07

回答:

大致压缩过程

  1. 原图宽或高只要有一边大于 240 则执行压缩处理

  2. 根据缩率图最大尺寸 240、最小尺寸 100 的要求加载图片文件(适度同比缩放原图)

  3. 将步骤 2 得到的图片按照原图 30% 的比例进行容量压缩

步骤 1、3 实现代码片段

private static final int THUMB_COMPRESSED_SIZE = 240;
private static final int THUMB_COMPRESSED_MIN_SIZE = 100;
private static final int THUMB_COMPRESSED_QUALITY = 30;

ImageMessage model = ...;    // 图片消息
String thumbPath = model.getThumUri().toString().substring(5);

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

BitmapFactory.decodeFile(thumbPath, options);
String imageFormat = options.outMimeType != null ? options.outMimeType : "";
// 1. 原图宽或高只要有一边大于 240 则执行压缩处理
if (options.outWidth > THUMB_COMPRESSED_SIZE || options.outHeight > THUMB_COMPRESSED_SIZE) {

    // 2. 根据缩率图最大尺寸 240、最小尺寸 100 的要求加载图片文件(适度同比缩放原图)
    Bitmap bitmap = getThumbBitmap(getContext(),
            model.getThumUri(),
            THUMB_COMPRESSED_SIZE,
            THUMB_COMPRESSED_MIN_SIZE);
    if (bitmap != null) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        // 3. 将步骤 2 得到的图片按照原图 30% 的比例进行容量压缩
        boolean success = bitmap.compress(Bitmap.CompressFormat.JPEG, THUMB_COMPRESSED_QUALITY, outputStream);
        // 在部分机型调用系统压缩转换png会有异常情况,修改后先进行判断是否压缩成功,如果压缩不成功则使用png方式进行二次压缩
        if (!success) {
            bitmap.compress(Bitmap.CompressFormat.PNG, THUMB_COMPRESSED_QUALITY, outputStream);
        }
        model.setBase64(Base64.encodeToString(outputStream.toByteArray(), Base64.NO_WRAP));
        outputStream.close();
        model.setThumUri(Uri.parse("file://" + uri.toString() + IMAGE_THUMBNAIL_PATH + name));
        if (!bitmap.isRecycled())
            bitmap.recycle();
    }
}

步骤 2 实现代码片段

public static Bitmap getThumbBitmap(Context context, @NonNull Uri uri, int sizeLimit, int minSize) throws IOException {

    String path;
    Bitmap result;

    if (("file").equals(uri.getScheme())) {
        path = uri.toString().substring(5);
    } else if (("content").equals(uri.getScheme())) {
        Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.Media.DATA}, null, null, null);
        if (cursor == null) {
            return null;
        }
        cursor.moveToFirst();
        path = cursor.getString(0);
        cursor.close();
    } else {
        return null;
    }

    ExifInterface exifInterface = new ExifInterface(path);

    Options options = new Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);

    int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);

    int width = options.outWidth;
    int height = options.outHeight;

    int longSide = (width > height) ? width : height;
    int shortSide = (width > height) ? height : width;
    float scale = (float) longSide / shortSide;
    int sampleW = 1, sampleH = 1;
    int sampleSize = 1;
    if (scale > (float) sizeLimit / minSize) {
        while (shortSide / 2 > minSize) {
            shortSide /= 2;
            sampleSize <<= 1;
        }
        options = new Options();
        options.inSampleSize = sampleSize;
    } else {
        while (width / 2 > sizeLimit) {
            width /= 2;
            sampleW <<= 1;
        }

        while (height / 2 > sizeLimit) {
            height /= 2;
            sampleH <<= 1;
        }

        options = new Options();
        sampleSize = Math.max(sampleW, sampleH);
        options.inSampleSize = sampleSize;
    }
    Bitmap bitmap;
    try {
        bitmap = BitmapFactory.decodeFile(path, options);
    } catch (OutOfMemoryError e) {
        options.inSampleSize = options.inSampleSize << 1;
        bitmap = BitmapFactory.decodeFile(path, options);
    }
    Matrix matrix = new Matrix();
    if (bitmap == null) {
        return null;
    }
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    if (orientation == ExifInterface.ORIENTATION_ROTATE_90
            || orientation == ExifInterface.ORIENTATION_ROTATE_270
            || orientation == ExifInterface.ORIENTATION_TRANSPOSE
            || orientation == ExifInterface.ORIENTATION_TRANSVERSE) {
        int tmp = w;
        w = h;
        h = tmp;
    }
    switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            matrix.setRotate(90, w / 2f, h / 2f);
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            matrix.setRotate(180, w / 2f, h / 2f);
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            matrix.setRotate(270, w / 2f, h / 2f);
            break;
        case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
            matrix.preScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_FLIP_VERTICAL:
            matrix.preScale(1, -1);
            break;
        case ExifInterface.ORIENTATION_TRANSPOSE:
            matrix.setRotate(90, w / 2f, h / 2f);
            matrix.preScale(1, -1);
            break;
        case ExifInterface.ORIENTATION_TRANSVERSE:
            matrix.setRotate(270, w / 2f, h / 2f);
            matrix.preScale(1, -1);
            break;
    }
    float sS = 0;
    float xS = 0;
    float yS = 0;
    if (scale > (float) sizeLimit / minSize) {
        shortSide = (bitmap.getWidth() > bitmap.getHeight()) ? bitmap.getHeight() : bitmap.getWidth();
        sS = (float) minSize / shortSide;
        matrix.postScale(sS, sS);
    } else {
        xS = (float) sizeLimit / bitmap.getWidth();
        yS = (float) sizeLimit / bitmap.getHeight();
        matrix.postScale(Math.min(xS, yS), Math.min(xS, yS));
    }
    int x = 0, y = 0;
    try {
        if (scale > (float) sizeLimit / minSize) {
            if (bitmap.getWidth() > bitmap.getHeight()) {
                h = bitmap.getHeight();
                w = h * sizeLimit / minSize;
                x = (bitmap.getWidth() - w) / 2;
                y = 0;
            } else {
                w = bitmap.getWidth();
                h = w * sizeLimit / minSize;
                x = 0;
                y = (bitmap.getHeight() - h) / 2;
            }
        } else {
            w = bitmap.getWidth();
            h = bitmap.getHeight();
        }
        result = Bitmap.createBitmap(bitmap, x, y, w, h, matrix, true);
    } catch (OutOfMemoryError e) {

        if (!bitmap.isRecycled())
            bitmap.recycle();
        return null;
    }
    if (!bitmap.isRecycled() && !bitmap.equals(result))
        bitmap.recycle();
    return result;
}

注意:以上示例代码为 Android 端实现,且使用了 Android 平台图片处理相关 API