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图片的资料请关注脚本之家其它相关文章!
