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