Android实现png转jpg图片的方法
作者:Katie。
一、项目概述
在 Android 应用开发中,图像处理是非常常见的需求。PNG 与 JPG 是两种最常见的图片格式:
PNG(Portable Network Graphics)支持透明通道、无损压缩,适合需要保持图像质量和透明度的场景;
JPG(Joint Photographic Experts Group)采用有损压缩,不支持透明,文件体积更小,适合照片展示与网络传输。
本项目的目标是:
在 Android 平台上实现一个 PNG 转 JPG 的模块,用户可以从相册或文件中选取 PNG 图片,一键将其转换为 JPG 并保存到本地。
核心功能点:
从系统相册或文件管理器中选择 PNG 文件
读取并解码为 Bitmap
处理透明通道(填充背景)
以 JPG 格式压缩并写入文件
返回保存路径,并可在界面中预览
二、技术背景与相关知识
要完成上述功能,需要掌握以下技术点:
1. 图片格式基础
PNG:
支持 RGBA 四通道,其中 A(Alpha)通道用于透明度
无损压缩,文件较大
适合图标、UI 元素、需要透明的场景
JPG:
只支持 RGB 三通道,不支持透明
有损压缩,可调压缩质量(0–100)
文件体积小,适合照片、展示图
2. Android Bitmap 原理
Bitmap 是 Android 处理图像的核心类,封装了像素数据。
配置选项:
ARGB_8888
:32 位,含透明,质量高RGB_565
:16 位,不含透明,内存占用更少
内存管理:
大图容易导致 OOM,需要适当缩放或使用
inSampleSize
使用完毕需调用
bitmap.recycle()
释放 native 内存
3. Canvas 与 Paint
Canvas:在 Bitmap 上绘制图形或其他 Bitmap
Paint:控制绘制效果,如抗锯齿、颜色滤镜等
绘制流程:
创建一个目标 Bitmap
用 Canvas 绑定该 Bitmap
通过 Canvas.drawXXX() 方法绘制
4. Android 文件存储
内部存储:私有,不需权限
外部存储私有目录(
getExternalFilesDir()
):无需额外权限,卸载时会被清除外部公有目录 / MediaStore:需运行时权限或使用 SAF
本项目使用外部私有目录,避免申请繁琐权限。
5. Uri 与 ContentResolver
系统选择器返回的不是文件路径,而是 Uri
需通过
context.getContentResolver().openInputStream(uri)
获取InputStream
6. Java I/O 与异常处理
使用
try–catch–finally
结构保证流关闭捕获
IOException
7. 动态权限(API 23+)
若使用公有外部存储,需要申请
WRITE_EXTERNAL_STORAGE
本例中使用私有目录,无需动态权限
三、项目实现思路
UI 交互
主界面提供“选择 PNG”“开始转换”按钮与 ImageView
选择图片
使用
Intent.ACTION_PICK
或Intent.ACTION_OPEN_DOCUMENT
限定类型为image/png
加载 Bitmap
通过
ContentResolver
打开 Uri 的InputStream
使用
BitmapFactory.decodeStream()
解码
创建目标 Bitmap
调用
Bitmap.createBitmap(width, height, Config.ARGB_8888)
处理透明通道
在 Canvas 上先绘制纯白背景,再绘制原 PNG
压缩与保存
使用
Bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream)
保存到
getExternalFilesDir("converted")
资源回收
调用
bitmap.recycle()
并关闭流
结果反馈
返回文件路径,UI 层显示预览并提示用户
四、完整代码(整合且注释详尽)
package com.example.pngtojpgconverter; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class MainActivity extends Activity { private static final int REQUEST_PICK_PNG = 1001; private ImageView imageView; private Button btnSelect, btnConvert; private Uri selectedUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定 UI 控件 imageView = findViewById(R.id.imageView); btnSelect = findViewById(R.id.btnSelect); btnConvert = findViewById(R.id.btnConvert); // 选择 PNG 按钮点击 btnSelect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 启动系统相册,仅显示 PNG Intent intent = new Intent(Intent.ACTION_PICK); intent.setType("image/png"); startActivityForResult(intent, REQUEST_PICK_PNG); } }); // 转换按钮点击 btnConvert.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 确保已选图片 if (selectedUri == null) { Toast.makeText(MainActivity.this, "请先选择 PNG 图片", Toast.LENGTH_SHORT).show(); return; } // 调用工具类执行转换 String jpgPath = ImageConverter.convertPngToJpg(MainActivity.this, selectedUri); if (jpgPath != null) { // 转换成功:提示并预览 Toast.makeText(MainActivity.this, "转换成功: " + jpgPath, Toast.LENGTH_LONG).show(); imageView.setImageURI(Uri.fromFile(new File(jpgPath))); } else { // 转换失败:提示 Toast.makeText(MainActivity.this, "转换失败", Toast.LENGTH_SHORT).show(); } } }); } // 处理选择结果 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_PICK_PNG && resultCode == RESULT_OK) { selectedUri = data.getData(); imageView.setImageURI(selectedUri); } } } // 工具类:执行 PNG 转 JPG class ImageConverter { private static final String TAG = "ImageConverter"; /** * 将 PNG 图像转换为 JPG 并保存 * * @param context 应用上下文 * @param pngUri PNG 图像的 Uri * @return 返回 JPG 文件绝对路径,失败返回 null */ public static String convertPngToJpg(Context context, Uri pngUri) { Bitmap srcBitmap = null; Bitmap dstBitmap = null; FileOutputStream fos = null; try { // 1. 打开 PNG 输入流 InputStream is = context.getContentResolver().openInputStream(pngUri); // 2. 解码为 Bitmap srcBitmap = BitmapFactory.decodeStream(is); if (srcBitmap == null) { Log.e(TAG, "解码 PNG Bitmap 失败"); return null; } // 3. 创建目标 Bitmap,使用 ARGB_8888 保留高质量 dstBitmap = Bitmap.createBitmap( srcBitmap.getWidth(), srcBitmap.getHeight(), Bitmap.Config.ARGB_8888 ); // 4. 使用 Canvas 绘制:白底 + 原图 Canvas canvas = new Canvas(dstBitmap); canvas.drawColor(Color.WHITE); // 填充白色背景 Paint paint = new Paint(); paint.setAntiAlias(true); // 抗锯齿 canvas.drawBitmap(srcBitmap, 0, 0, paint); // 5. 准备输出文件 File outDir = context.getExternalFilesDir("converted"); if (outDir != null && !outDir.exists()) { outDir.mkdirs(); } File jpgFile = new File(outDir, "img_" + System.currentTimeMillis() + ".jpg"); fos = new FileOutputStream(jpgFile); // 6. 压缩为 JPG,质量 90% boolean ok = dstBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); fos.flush(); if (ok) { Log.i(TAG, "JPG 保存成功: " + jpgFile.getAbsolutePath()); return jpgFile.getAbsolutePath(); } else { Log.e(TAG, "Bitmap.compress 返回 false"); return null; } } catch (IOException e) { Log.e(TAG, "转换异常: " + e.getMessage()); return null; } finally { // 7. 资源释放 if (srcBitmap != null) srcBitmap.recycle(); if (dstBitmap != null) dstBitmap.recycle(); if (fos != null) { try { fos.close(); } catch (IOException ignored) {} } } } }
五、代码解读
onActivityResult(...)
处理系统返回的 PNG 文件 Uri,并在 ImageView 中展示,供用户确认。convertPngToJpg(...)
打开 PNG 输入流,解码为源 Bitmap;
创建目标 Bitmap(ARGB_8888);
用 Canvas 绘制白色背景,再绘制源 Bitmap,消除透明区域的黑底问题;
准备输出文件路径(App 私有外部存储),创建目录;
调用
compress(JPEG, 90, fos)
将目标 Bitmap 以 JPG 格式写入文件;释放 Bitmap 与关闭流。
六、项目总结与拓展
核心技术点回顾
Bitmap 解码与创建
Canvas 绘图与透明处理
Bitmap.compress 压缩与文件写入
Uri → InputStream → Bitmap 的流程
外部私有目录的使用,避免权限复杂化
性能与稳定性
使用
ARGB_8888
保证质量,必要时可改为RGB_565
以节省内存;对大图可先按需缩放,避免 OOM;
确保在 finally 中释放资源,防止内存泄漏。
可扩展功能
批量转换:遍历多张图片,使用线程池并发处理;
动态压缩质量:在 UI 上添加 SeekBar,用户可调整质量值;
其他格式支持:扩展到 PNG→WEBP、BMP→JPG 等;
保存到系统相册:通过 MediaStore API 将 JPG 添加到相册;
透明背景自定义:允许用户选择背景色,而非固定白色;
错误反馈:增强异常捕获,向用户展示详细错误原因;
进度展示:批量转换时显示进度条或通知。
学习要点
深入理解 Android 图像处理流程;
掌握文件存储最佳实践;
熟悉常见 Bitmap 配置与内存优化技巧;
掌握使用 Canvas 对位图进行二次加工。
以上就是Android实现png转jpg图片的方法的详细内容,更多关于Android png转jpg图片的资料请关注脚本之家其它相关文章!