在 Android 中调整图片大小同时仍保持质量

2024-01-22

我想将图像文件大小减小到 100 KB 以下,同时保持图像质量,就像 Whatsapp 和 Facebook 所做的那样。

我尝试了 stackoverflow 上几乎所有可用的 android 图像压缩代码,但这对我不起作用。

现在我正在关注这个博客 http://voidcanvas.com/whatsapp-like-image-compression-in-android/为了减小图像大小,我得到的图像低于 100 KB,但图像质量很差。

有什么方法可以将图像大小减小到 100 KB 以下 保持品质??? (原始图像大小可能从 20 KB 到 8 MB 不等)

我在Java项目中尝试了JAI库,效果很好。

我可以在android中使用JAI库来减小图像大小吗???

提前致谢。

压缩图像的源代码:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.media.ExifInterface;
import android.os.Environment;
import android.util.Log;

public class CompressBitmap {

    private String path;
    public CompressBitmap(String path){
        this.path= path;
    }

    public ByteArrayOutputStream getBitmap(){
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        getscaledImage(path).compress(Bitmap.CompressFormat.JPEG, 100, outStream);
        return outStream;
    }

    public ByteArrayOutputStream getBitmap(int quality){
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        getscaledImage(path).compress(Bitmap.CompressFormat.JPEG, quality, outStream);  
        return outStream;
    }

    public String getComressFile(){
        FileOutputStream out = null;
        String filename = createImageFile();
        try {
            out = new FileOutputStream(filename);
            getscaledImage(path).compress(Bitmap.CompressFormat.JPEG, 80, out);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        File file = new File(filename);
        Log.e("SIze of Image","Length"+file.length());
        return filename;
    }

    private Bitmap getscaledImage(String filePath){
        Bitmap scaledBitmap = null;

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;                      
        Bitmap bmp = BitmapFactory.decodeFile(filePath,options);

        int actualHeight = options.outHeight;
        int actualWidth = options.outWidth;
        float maxHeight = 800.0f;
        float maxWidth = 600.0f;
        float imgRatio = actualWidth / actualHeight;
        float maxRatio = maxWidth / maxHeight;

        Log.v("Pictures", "Before scaling Width and height are " + actualWidth + "--" + actualHeight);

        if (actualHeight > maxHeight || actualWidth > maxWidth) {
            if (imgRatio < maxRatio) {
                imgRatio = maxHeight / actualHeight;
                actualWidth = (int) (imgRatio * actualWidth);
                actualHeight = (int) maxHeight;
            } else if (imgRatio > maxRatio) {
                imgRatio = maxWidth / actualWidth;
                actualHeight = (int) (imgRatio * actualHeight);
                actualWidth = (int) maxWidth;
            } else {
                actualHeight = (int) maxHeight;
                actualWidth = (int) maxWidth;     
            }
        }

        options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);
        options.inJustDecodeBounds = false;
        options.inDither = false;
        options.inPurgeable = true;
        options.inInputShareable = true;
        options.inTempStorage = new byte[16*1024];

        try{    
            bmp = BitmapFactory.decodeFile(filePath,options);
        }
        catch(OutOfMemoryError exception){
            exception.printStackTrace();

        }
        try{
            scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888);
        }
        catch(OutOfMemoryError exception){
            exception.printStackTrace();
        }

        float ratioX = actualWidth / (float) options.outWidth;
        float ratioY = actualHeight / (float)options.outHeight;
        float middleX = actualWidth / 2.0f;
        float middleY = actualHeight / 2.0f;

        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);

        Canvas canvas = new Canvas(scaledBitmap);
        canvas.setMatrix(scaleMatrix);
        canvas.drawBitmap(bmp, middleX - bmp.getWidth()/2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));

        Log.v("Pictures", "After scaling Width and height are " + scaledBitmap.getWidth() + "--" + scaledBitmap.getHeight());

        ExifInterface exif;
        try {
            exif = new ExifInterface(filePath);

            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
            Log.d("EXIF", "Exif: " + orientation);
            Matrix matrix = new Matrix();
            if (orientation == 6) {
                matrix.postRotate(90);
                Log.d("EXIF", "Exif: " + orientation);
            } else if (orientation == 3) {
                matrix.postRotate(180);
                Log.d("EXIF", "Exif: " + orientation);
            } else if (orientation == 8) {
                matrix.postRotate(270);
                Log.d("EXIF", "Exif: " + orientation);
            }
            scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return scaledBitmap;
    }

    private String createImageFile(){
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",Locale.getDefault()).format(new Date());
            String imageFileName = "JPEG_" + timeStamp + "_";
            File storageDir = Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_PICTURES);
            File image;
            try {
                image = File.createTempFile(
                    imageFileName,  /* prefix */
                    ".jpg",         /* suffix */
                    storageDir      /* directory */
                );
                return image.getAbsolutePath();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
    }

    private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        final float totalPixels = width * height;
        final float totalReqPixelsCap = reqWidth * reqHeight * 2;

        while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
            inSampleSize++;
        }
        return inSampleSize;
    }
}

public void getBase64() {
    CompressBitmap compressBitmap =  new CompressBitmap(picturePath);  
    //display compressBitmap in ImageView.

    byte[] bytes=null;

    File file= new File(picturePath);               

    ByteArrayOutputStream bos = compressBitmap.getBitmap();
    bytes = bos.toByteArray(); 
    base64 = Base64.encodeToString(bytes, Base64.DEFAULT);

    return base64;   // send base64 String on server
}

似乎缺少:

options.inPreferQualityOverSpeed = true;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Android 中调整图片大小同时仍保持质量 的相关文章

随机推荐

  • 从参数化触发器插件传回结果

    我有 2 个工作 Helper 和 Main 以及单个 jenkins 实例 即主机和执行器 帮助程序管理第 3 方资源并为主要作业做好准备 准确地说 它为要部署的应用程序进行测试创建环境 辅助作业的唯一工件是一个单独的文件 其中包含专为主
  • 将具有重复键的键值数组转换为具有唯一键和值数组属性的对象数组

    我有一个键 值对数组 键有时会重复 并且每个键的值始终是唯一的 我想将每个唯一的键压缩为一个对象 这样我就有一个键和一个关联值的数组作为属性 有没有方便的 JavaScript 函数可以做到这一点 This pairArray key a
  • 使用 FFmpeg 从大电影创建缩略图需要太长时间

    我正在使用这个 shell 命令从 123 秒的 VIDEO FILE 中制作缩略图并将其保存到 THUMBNAIL FILE 中 ffmpeg i VIDEO FILE r 1 ss 123 f image2 THUMBNAIL FILE
  • 我可以在 GridView 中合并页脚吗?

    我有一个与数据集绑定的 GridView 我有我的页脚 它由列线分隔 我想合并 2 列 我怎么做
  • 将预编译模板与 Handlebars.js 结合使用(jQuery Mobile 环境)

    我在 Handlebars 中的模板预编译方面遇到了一些困难 我的 jQuery Mobile 项目在模板方面变得相当大 我希望预编译我使用的模板 然而 我似乎找不到关于如何使用车把执行此操作的良好解释 例如分步教程 我仍然使用脚本标签将模
  • 如何让只有授权用户才能访问存储在 Amazon S3 中的内容?

    一旦您将内容存储在 S3 中并将其公开 那么每个人都可以访问它 有没有办法让只有授权用户才能访问S3中存储的内容 例如 我有一个允许人们存储文档的网站 服务器将这些文档存储在 S3 中 我希望只有上传该文档的用户才能访问它 我知道我可以将
  • 无法对 DependencyProperty 进行数据绑定

    我有一个带有 DependencyProperty 的 UserControl 我使用数据绑定表达式在主机窗口中设置它的值 但是 它并没有按预期工作 用户控件的代码隐藏片段 public class ViewBase UserControl
  • 带有 JSON 数据的 DataTable

    我正在尝试使用 DataTable 创建一个表 但很难让 DataTable 使用 JSON 对象加载 function getData var request new XMLHttpRequest var json link to my
  • MPMoviePlayerController 与启动 UIWebView 来流电影的优缺点

    我有一位客户拥有 Flash 格式的网络视频内容 我的任务是帮助他们在 iPhone 应用程序中展示视频 我意识到第一步是将这些视频转换为适合 iPhone 的 Quicktime 格式 然后我必须帮助客户弄清楚如何或在哪里托管这些文件 如
  • python列表中的索引错误

    B l append l i A B l 这里是一个列表 我试图向其中附加更多值以使其充当数组 但它仍然给我错误 如列表索引超出范围 如何摆脱它 您的代码存在很多问题 1 the append method 不返回任何内容 所以这样写是没有
  • SQL-如何将 YYYYMM 数字转换为日期

    所以我对 SQL 还很陌生 我有一个充满数字的列 以 YYYYMM 格式列出年份和月份 即 2016 年 7 月的 201607 我想知道是否可以在 SQL 中将其转换为正确的日期格式 我已经做了相当多的研究 并且看到了很多关于将 YYYY
  • 如何发送 zip 文件而不在物理位置创建它?

    我想发送带有 zip 文件附件的电子邮件 我可以发送 pdf 文件 而无需使用 ByteArrayOutputStream 将它们保存在物理位置 但是当我尝试压缩这些文件并发送它时它不起作用 它给出了非法附件的异常 下面是我编写的用于创建
  • 从 iOS 中的离屏 OpenGL 像素缓冲区读取像素 (OopenGL-ES)

    我想从屏幕外 不受 CAEAGLLayer 支持 帧缓冲区读取像素 我创建缓冲区的代码如下所示 glGenFramebuffersOES 1 storeFramebuffer glGenRenderbuffersOES 1 storeRen
  • Woocommerce 订单数量的倍数

    我试图将 woocommerce 限制为仅以 5 10 或 15 的固定数量进行销售 下面的代码片段 我在这个论坛上找到的 允许我将最小数量设置为 5 但我想知道是否有人可以建议是否可以将其修改为允许 5 10 或 15 我感谢您提供的任何
  • 如何找到文本光标的全局位置?

    我想执行一个QMenu http qt nokia com doc 4 0 qmenu html文本光标位置处的对象QPlainTextEdit http doc trolltech com main snapshot qplaintext
  • 你最喜欢的 C++ 编码风格习语是什么 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何使用 use_library('django','1.2')

    我正在学习在 Google App Engine 中进行开发 这是教程中的代码之一 http code google com appengine docs python gettingstarted usingwebapp html htt
  • 如何防止在 twitter bootstrap typeahead 插件中按 Enter 键提交

    我有一个输入文本 我应用它的预输入插件来建议项目 但是当我在输入文本上按 Enter 键时 它会提交表单 如何使用 twitter bootstrap typeahead 插件阻止表单提交 您可以通过向特定输入添加 ID 并简单地删除 En
  • git flow 发布选定的功能

    我正在尝试向我的团队介绍 Git 流程 我们是一个相当小的团队 而且非常敏捷 我们希望每天发布一次 这意味着我们测试当天所有更改的时间有限 业务团队希望能够控制正在发布的功能 尽管这并不理想 Git 流程似乎不能很好地适应这一点 从开发中删
  • 在 Android 中调整图片大小同时仍保持质量

    我想将图像文件大小减小到 100 KB 以下 同时保持图像质量 就像 Whatsapp 和 Facebook 所做的那样 我尝试了 stackoverflow 上几乎所有可用的 android 图像压缩代码 但这对我不起作用 现在我正在关注