图片所遇到的坑

news/2024/10/22 11:01:59/

本文记录使用Android时关于图片所遇到的坑。

主要记录以下问题:

  • 如何获取相册中的图片
  • 如何剪裁所得到的图片
  • 如何拍照并剪裁图片
  • 如何压缩图片
  • 图片保存在手机本地的存取
  • 图片在APP与服务器之间的传输

如何获取相册中的图片


简单来说,我们就是要写一个Intent去相册中挑选图片,见代码:

Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI);
startActivityForResult(intent, GET_FROM_GALLERY);

这样我们就能改onActivtyResult中接收的到的数据:

    @Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode) {case GET_FROM_GALLERY:if(resultCode == Activity.RESULT_OK){//获取所选照片的URIUri selectedImage = data.getData();
//                    设置照片
//                    Bitmap bitmap = null;
//                    try {
//                        bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);
//                    } catch (IOException e) {
//                        e.printStackTrace();
//                    }
//                    image.setImageBitmap(bitmap);performCrop(selectedImage);}break;

这样我们就能简单的获得所选图片的Uri,从而进一步对图片操作,剪裁图片的方法就再performCrop(selectedImage)里。如果你想直接将所选择的图片设置起来,就是上面代码片段中被注释掉的那一部分了。

如何剪裁所得到的图片


首先我们要的到图片的Uri,然后再写一个Intent,没错,剪裁其实是调用了系统的图片编辑器,所以还是要用Intent,如果你想实现自己的剪裁器或某些特效(比如微信的头像剪裁),那就要辛苦一下自己写个工具类了。

关于启动系统剪裁的Intent是这么写的:

/*** 剪裁图片, 要得到图片的uri才能使用, 可以先启动选择图片的intent, 然后在onActivityResult中* 得到uri, 然后再调用这个方法* @param contentUri 需要剪裁的图片的uri*/private void performCrop(Uri contentUri) {try {//Start Crop ActivityIntent cropIntent = new Intent("com.android.camera.action.CROP");cropIntent.setDataAndType(contentUri, "image/*");// set crop propertiescropIntent.putExtra("crop", "true");// indicate aspect of desired cropcropIntent.putExtra("aspectX", 1);cropIntent.putExtra("aspectY", 1);// indicate output X and YcropIntent.putExtra("outputX", 280);cropIntent.putExtra("outputY", 280);// retrieve data on returncropIntent.putExtra("return-data", true);// start the activity - we handle returning in onActivityResultstartActivityForResult(cropIntent, GET_FROM_GALLERY_CROP);}// respond to users whose devices do not support the crop actioncatch (ActivityNotFoundException anfe) {// display an error messageString errorMessage = "your device doesn't support the crop action!";Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);toast.show();}}

我们看到Intent中设置了一些参数,比如剪裁图片的位置,还有剪裁图片的宽高比例,见名知意,我就不解释了。如果我们完成剪裁,那么接下来还是要在onActivityResult()方法中接受数据:

            case GET_FROM_GALLERY_CROP:if(resultCode == Activity.RESULT_OK){//设置Bundle extras = data.getExtras();Bitmap selectedBitmap = extras.getParcelable("data");image.setImageBitmap(selectedBitmap);

这样得到bitmap就是符合我们要求的bitmap了。

如何拍照并剪裁图片


当然了,剪裁图片不只一种方式,那我们该如何通过拍照获得图片并剪裁呢?
首先当然还是要写一个Intent,然后使用这个Intent去启动系统相机应用获得照片:

/*** 创建拍照的intent并存放照片的文件*/private void dispatchTakePictureIntent() {Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);if (takePictureIntent.resolveActivity(getPackageManager()) != null) {File photoFile = null;try {photoFile = createImageFile(loginUserPrefix);} catch (IOException ex) {Log.e("LocalImageTest", "创建存储文件失败");}if (photoFile != null) {Uri photoURI = Uri.fromFile(photoFile);takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);startActivityForResult(takePictureIntent, GET_FROM_CAMERA);}}}

上面的代码除了简单的启动了相机之外,还指定了文件的存储位置。这样可以方便对图片存取的操作,在下面几节,这就不索罗。

那在得到了图片之后我们该怎么做了,当然还是老一套,先得到图片的Uri,然后写一个Intent去启动系统的剪裁应用呗:

            case GET_FROM_CAMERA:if(resultCode == Activity.RESULT_OK){Uri selectedImage = Uri.fromFile(new File(mCurrentPhotoPath));performCrop(selectedImage);}break;

在onActivity中接受图片,然后把图片的Uri得到,位置我们之前已经将图片保存的文件创建好了,所以这里可以很简单就得到Uri。

如何压缩图片


        FileOutputStream out = null;try {out = new FileOutputStream(mCurrentPhotoPath);bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out);

压缩图片相对来说比较简单,只是调用了一个方法就完成了,需要创建一个输出流,对应的是压缩之后的图片的位置。

图片在手机本地的存取


一般每个应用在手机里都有一个自己的文件夹,用于存储本应用的图片以及其他文件,所以这一部分可以说是在APP开发过程中很重要的一步。

我写了一个工具类,里面是关于图片在手机中存取的整个方法,每个方法都由注释,名字也很好懂,我就不啰嗦了:

package utils;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class FileUtils {public static final String HAPPY_GO = "HappyGo";public static final String PHOTO_SUFFIX = ".jpg";public static final String TAG = "TAG";public static final File APP_DIR = new File(Environment.getExternalStorageDirectory(), HAPPY_GO);/*** 从文件中加载bitmap* @param name 文件名* @return Bitmap对象*/public static Bitmap loadImageFromStorage(String name){if (!APP_DIR.exists()) {if(!APP_DIR.mkdir()){Log.e(TAG, "创建App_Dir失败");return null;}}File file = getMediaFile(name);Bitmap bitmap = null;try {bitmap = BitmapFactory.decodeStream(new FileInputStream(file));} catch (FileNotFoundException e) {e.printStackTrace();}finally {return bitmap;}}/*** 将bitmap存储到文件中* @param name 文件名* @param image bitmap*/public static void storeImageIntoStorage(String name, Bitmap image) {File pictureFile = getMediaFile(name);if (pictureFile == null) {Log.e(TAG, "Error creating media file, check storage permissions: ");return;}try {FileOutputStream fos = new FileOutputStream(pictureFile);image.compress(Bitmap.CompressFormat.JPEG, 100, fos);fos.close();} catch (FileNotFoundException e) {Log.d(TAG, "File not found: " + e.getMessage());} catch (IOException e) {Log.d(TAG, "Error accessing file: " + e.getMessage());}}/*** 创建文件* @param name 文件名* @return File对象*/public static File getMediaFile(String name){File mediaFile;String fileName = name + PHOTO_SUFFIX;mediaFile = new File(APP_DIR, fileName);return mediaFile;}/*** 删除文件* @param name 文件名* @return 删除成功则返回true*/public static boolean deleteMediaFile(String name){File mediaFile;String fileName = name + PHOTO_SUFFIX;mediaFile = new File(APP_DIR, fileName);boolean result = mediaFile.delete();return result;}}

图片在APP与服务器之间的传输

如果要实现一个上传头像的功能,我相信图片在APP和服务器之间的传输是必不可少的,那么传输到底该怎么传呢?可不是直接传一个bitmap,一般后台都没这个类。我的方式是把图片转码成字符串,然后将这个字符串传给后台,保存在数据库,然后需要的时候,后台在把这个由图片转变来的字符串传回前端。

当然了,这里涉及一个工具类,把一个图片文件转码成字符串。这个jar包是BASE64Encoder。

有个这个jar包,我们就能直接写两个方法,实现字符串和文件之间的相互转化了:

/*** 将手机内存的某一图片转化为字符串* @param fileName 文件名* @return 字符串*/public static String changePictureIntoString(String fileName) {byte[] data = null;String path = FileUtils.getMediaFile(fileName).getAbsolutePath();try {InputStream in = new FileInputStream(path);data = new byte[in.available()];in.read(data);in.close();} catch (IOException e) {e.printStackTrace();}BASE64Encoder encoder = new BASE64Encoder();return encoder.encode(data);}/*** 将字符串还原成jpg图片,然后存储在手机内存中* @param imgStr 图片对应的字符串* @param fileName 文件名* @return 操作是否成功, true表示成功*/public static boolean changeStringToPictureAndSave(String imgStr, String fileName) {if (imgStr == null)return false;BASE64Decoder decoder = new BASE64Decoder();try {// Base64解码byte[] bytes = decoder.decodeBuffer(imgStr);for (int i = 0; i < bytes.length; ++i) {if (bytes[i] < 0) {bytes[i] += 256;}}//获取文件的绝对路径String path = FileUtils.getMediaFile(fileName).getAbsolutePath();//将数据保存到文件中OutputStream out = new FileOutputStream(path);out.write(bytes);out.flush();out.close();return true;} catch (Exception e) {return false;}}/*** 将字符串直接转化为bitmap* @param string 字符串* @return bitmap*/public static Bitmap stringToBitmap(String string){Bitmap bitmap=null;try {byte[]bitmapArray;bitmapArray= Base64.decode(string, Base64.DEFAULT);bitmap= BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length);} catch (Exception e) {e.printStackTrace();}return bitmap;}/*** 将bitmap直接转化为字符串* @param bitmap bitmap* @return 字符串*/public static String bitmapToString(Bitmap bitmap){String string=null;ByteArrayOutputStream bStream=new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.JPEG, 30, bStream);byte[]bytes=bStream.toByteArray();string= Base64.encodeToString(bytes, Base64.DEFAULT);return string;}

这里有四个方法,前两个方法是需要文件操作的,而后面两个方法是很简单,直接实现字符串和bitmap对象之前的相互转化,不过它的代码是原本10k的文件变成了160k-220k的文件,在服务器上很占地方,而且传输很慢,很消耗流量。所以我还是推荐使用前两个方法。方法都由解释,我就不复述了。


http://www.ppmy.cn/news/499626.html

相关文章

cr3是什么格式?cr3格式用什么软件打开?cr3格式怎么转换成jpg

前言 第一次遇见cr3格式的朋友们&#xff0c;一定会有下列疑惑&#xff1a; cr3是什么格式&#xff1f;cr3格式怎么打开&#xff1f;cr3文件怎么转换jpg&#xff1f;cr3文件怎么转换png&#xff1f;cr3文件怎么转换gif&#xff1f; 今天我们就来一个个的解释下你的疑惑。 c…

分析一块某宝上的WiFi摄像头模块

某宝上的一个WiFi摄像头模块&#xff0c;有APP支持&#xff0c;可以装在航模上面。几十块钱的东西&#xff0c;好奇是怎么做的、用的是什么芯片。  拆出来的主板正面就是这样的背面只焊接了一根天线&#xff0c;电路真的是太简单了&#xff01; 一块未知的板子&#xff0c;只…

Capture One快捷键

文件 新会话...Ctrl+N新目录…Ctrl+Shift+N打开…Ctrl+O导入图像Ctrl+Shift+I移动到选择文件夹Ctrl+J重命名图像F2删除(D)Ctrl+Delete永久删除Alt+Delete处理Ctrl+D打印Ctrl+P编辑 撤销 (R)Ctrl+Y取消全选Ctrl+Shift+A反向选择Ctrl+I选择上一个Ctrl+Left选择下一个Ctrl+Right选…

技术分享|一种多智能体空地协同算法开发验证平台

空地协作属于多智能体协作中的异构智能体协作&#xff0c;是当今多智能体研究领域的热点。系统分利用了异构多机器人的功能互补性&#xff0c;组成跨域协作系统&#xff0c;实现任务协同和信息共享&#xff0c;从本质上提升了面对复杂环境和任务规划的感知能力、执行能力和运行…

arw是什么格式?arw格式用什么软件打开?arw格式怎么转换成jpg

前言 第一次遇见arw格式的朋友们&#xff0c;一定会有下列疑惑&#xff1a; arw是什么格式&#xff1f;arw格式怎么打开&#xff1f;arw文件怎么转换jpg&#xff1f;arw文件怎么转换png&#xff1f;arw文件怎么转换gif&#xff1f; 今天我们就来一个个的解释下你的疑惑。 a…

各种被墙的情况下.飞思卡尔-iMx SDK下载与安装

最近调飞思卡尔iMx6Q的硬件编解码,需要找sdk参考.故此根据nxp官方手册,下载与安装sdk包环境 因为很多关键网址被TG樯了.所以花了九牛二虎之力才down下了sdk. 故此笔记如下: 这是飞思卡尔官方的安装教程.我在其中做出备注. 官方GIT仓库位置如下:https://github.com/xtianbetz/…

免费文字转语音软件哪个好?推荐这三款文字转语音软件给你

文字转语音软件可以将我们输入的文字内容转化为人声朗读出来&#xff0c;这在很多场合都非常实用。比如&#xff0c;在开车或者做家务时&#xff0c;无法手持手机进行阅读&#xff0c;但是通过文字转语音功能&#xff0c;就可以轻松地听取所需内容。然而&#xff0c;市面上的文…

Capture One Pro 12.0.1中文版l飞思RAW软件Capture One 12.0.1MacOS系统

Capture One Pro 12.0.1win中文版 | Capture One Pro 12.0.1Mac中文版 Capture One Pro 12.0.1win中文版 | Capture One Pro 12.0.1Mac中文版 apture One PRO的工作流程采用了很多高级专业数码摄影师的意见&#xff0c;包含的工具和功能都是专业摄影师所需要的&#xff0c;飞…