webapp中html5调用系统相机拍照问题
一. 引言:
webapp之所以现在很流行,主要是现在的手机硬件配置都过剩了,用网页做的UI界面流畅度上与原生的差距很小,关键是开发速度得到了很大的提升,而且可以跨平台,IOS和Android可以使用同一界面,但是其中也会有一些问题,这里就说说调用系统相机出现的问题。
二. 在webapp中调用系统相机拍照存在的问题:
1. 部分手机通过html5调用系统相机拍照时,生成的照片是被旋转的。代表机型:小米6(Android8.0)
2. 部分手机拍照后点击确认,没有照片数据返回。代表机型: 红米note4(Android6.0)
3. 部分手机拍照后,点击确认键无任何反应。代表机型:魅族5(Android5.1)
三. 解决方法
1. 对于部分手机拍照后被旋转的问题,由于不是原生写的自定义相机,所以不能在拍照时候使用重力感应器等来矫正图片的旋转角度,而解决该类问题的方式也很简单,就是在系统相机拍完后会返回路径地址,我们拿到图片后,开始读取图片里面的orientation方向信息,当角度值为0的时候就不用旋转了,否则就要进行旋转。
/**
* 获取图片正确显示需要旋转的角度(顺时针)
* @return
*/
public static String getRotateAngleForPhoto(String filePath){
File file = new File(filePath);
int angle = 0;
try {
Metadata metadata = JpegMetadataReader.readMetadata(file);
Directory directory = metadata.getDirectory(ExifDirectory.class);
if(directory.containsTag(ExifDirectory.TAG_ORIENTATION)){
// Exif信息中方向
int orientation = directory.getInt(ExifDirectory.TAG_ORIENTATION);
// 原图片的方向信息
if(6 == orientation ){
//6旋转90
angle = 90;
}else if( 3 == orientation){
//3旋转180
angle = 180;
}else if( 8 == orientation){
//8旋转90
angle = 270;
}
}
} catch (JpegProcessingException e) {
e.printStackTrace();
} catch (MetadataException e) {
e.printStackTrace();
}
return angle+"";
}
拿到方向信息后,并可以进行校正图片的旋转角度了,矫正的时候,需要将图片文件转化成Bitmap,
//读取拍照生成的照片
FileInputStream is = new FileInputStream(new File(sourcePath));
//转化成Bitmap
Bitmap bitmap = BitmapFactory.decodeStream(is);
再通过方向信息将Bitmap图片进行旋转。
/**
* 旋转图片
*
* @param angle 旋转角度
* @param bitmap 要旋转的图片
* @return 旋转后的图片
*/
public static Bitmap rotate(Bitmap bitmap, int angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
}
旋转后返回的仍是Bitmap,需要转化为文件,可以直接替换掉源文件:
/**
* 保存图片
* @return
*/
public static void saveImageFile(String savepath,Bitmap bmp) {
File f = new File(savepath);
try {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f));
bmp.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bmp != null && !bmp.isRecycled()) {
bmp.recycle();
bmp = null;
}
}
}
以上的步骤大致为:获取旋转的角度信息 -> 原图片转成Bitmap -> 根据角度信息去旋转生成Bitmap -> 将Bitmap转化成图片文件
中间显然走了弯路,有没有可能根据方向角度信息直接把图片文件进行旋转呢,答案是肯定的,可以使用java桌面编程的awt包,不过我在android中没有成功过,代码是网上找的:
/**
* 旋转图片
* @param fullPath
* @param angel
* @return
*/
public static String rotatePhonePhoto(String fullPath, int angel){
BufferedImage src;
try {
src = ImageIO.read(new File(fullPath));
int src_width = src.getWidth(null);
int src_height = src.getHeight(null);
int swidth=src_width;
int sheight=src_height;
if(angel==90||angel==270){
swidth = src_height;
sheight= src_width;
}
Rectangle rect_des = new Rectangle(new Dimension(swidth,sheight));
BufferedImage res = new BufferedImage(rect_des.width, rect_des.height,BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = res.createGraphics();
g2.translate((rect_des.width - src_width) / 2,(rect_des.height - src_height) / 2);
g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
g2.drawImage(src, null, null);
ImageIO.write(res, "jpg", new File(fullPath));
} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
}
return fullPath;
}
上面会用到jar包:借助mediautil-1.0.jar,metadata-extractor-2.3.1.jar,
2. 部分手机拍照后,点击确认,没有数据返回,测试的时候是红米note4上出现的这种问题,从网上找了一些资料看了,发现是文件夹权限问题
(1). Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath()+ "/WebViewUploadImage";
(2). Environment.getExternalStorageDirectory().getPath() + "/WebViewUploadImage";
之前是使用了第二种,之后调整为第一种,红米note4上就没有问题了。
3. 部分手机点击确认无反应,从log上观察到了很奇怪的问题,网页点击拍照后跳转到系统相机后,日志随着点击完成按钮,就开始消失了,就开始怀疑是不是跳转到系统相机后,我猜想可能跟activity入栈有关,按照这个思路找资料,发现确实有人遇到这种问题,在Intent跳转时加上就可以了。
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);