一、项目概述
在 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图片的资料请关注代码网其它相关文章!
发表评论