序文
同社は以前に上記の試験機でのいくつかの変更が正常にテストされた後、ときにそれを、それは画面の水平方向の位置に回転していないことが判明先祖カスタムカメラでプロジェクトを、持っています。オンライン後で電話の一部のみが正しく回転し、いくつかの努力の後、最終的に解決されることを見出しました。そして、最終的に異なるのオンライン比較してステレオタイプ化画像回転できますまれな、高速回転スキームを。
この問題を解決するために、次のレコード、内部の問題のステップ解析による工程の後に、この記事を書きました。
携帯電話の一部のみが右回転します
このアプローチは、部分的にしか正しい回転式の携帯電話がonPictureTakenは()で処理するためのコールバックメソッド内のコードで、お使いのカメラの外観から直接写真を得ることです:
public void onPictureTaken(byte[] data, Camera camera) {
camera.stopPreview();
//是否需要旋转
boolean isOrientation = false;
//用户是否横屏拍摄,true为横屏 0度左旋 90不旋 180右旋 270度旋
if (CameraActivity.this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE
&& (takePhotoOrientation <= 90+45)&&(takePhotoOrientation>=90-45)) {//不旋转
isOrientation = false;
} else {
isOrientation = true;
}
//旋转太过消耗时间,是储存的40倍时间左右,考虑后去掉旋转。
//---反注释start---
if (isOrientation) {
//横屏拍摄,需要旋转90度
byte[] bytes = ImageUtils.rotatePic(data,takePhotoOrientation-90);
if (bytes != null) {
data = bytes;
}
}
//---反注释end---
mPicPath = String.format("%s%s%s", AppConfig.getCarTradeFileDir("Camera"),
System.currentTimeMillis() + ".jpg", tempFileSuffex);
FileSaveUtils.saveFile(data, mPicPath, new FileSaveUtils.SaveListener() {
@Override
public void saveComplete() {
finish();
}
});
}
复制代码
実際に、私は抗注釈付きの回転にコードを入れてやって来ました。
分析は、内部で行わ:
- この変数は、電話機の現在の状態によって決定されたリスナー重力によって提供されるtakePhotoOrientationが水平位置にあるとき、水平方向の位置を回転させる必要があります。
- そして、あなたは、コードの原作者がコメント回転が非常に時間がかかり、それを回転させていない私たちを警告し、その後、コードはコメントアウト回転ところに非常に近いことがわかります、私は彼に解決メモを取っていました。
- ImageUtils.rotatePicは()コアコードの内部で行って、画像を回転させ、オンライン検索でローテーションスキームであります:
public static byte[] rotatePic(byte[] data, int degree) {
byte[] bytes = null;
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inJustDecodeBounds = false;
options.inPurgeable = true;
options.inInputShareable = true;
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);// data是字节数据,将其解析成位图
bitmap = rotateBitmap(bitmap, degree);
bytes = bitmap2Bytes(bitmap);
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
} catch (Error e) {
e.printStackTrace();
}
return bytes;
}
/**
* 网上一搜就有的旋转代码
*/
public static Bitmap rotateBitmap(Bitmap bitmap, int degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap bm = null;
try {
bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
} catch (Exception e) {
bm = bitmap;
}
return bm;
}
public static byte[] bitmap2Bytes(Bitmap bm) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
return baos.toByteArray();
}
复制代码
- バイト[]のデータを保存します。ここに達成するために内部フォト保管方法も問題ですが、これは私たちの記事の焦点ではないので、まずそれを無視します。
それは〜はい、学生の何人かは作者が40倍の時間で回転を言った理由を確認するために目撃されている可能性があり、ここを参照してください
ImageUtils.rotatePic()の問題である:それは[]最初のバイトのビットマップに解析し、その後回転ビットマップを作成し、ストアに[]ビットマップのバイトに変換されます。このプロセスは、私が練習していなかったではない40回を持っていますが、それは長い時間がかかると想像します。最適化させました。
EXIFを取得
回転 - ビジネスの問題を解決するための最初のもの下の最適化。
どのように我々はそれの絵で方向ということを知ることができますか?小型ケース、それは、このような絞り、焦点距離、シャッター速度など、最も重要なように写真、に関する多くの情報内に格納され、EXIFの写真情報と呼ばれるホールドをそこに置かれる時、私は、カメラのカメラを撮影を再生するために打ちますそこに我々は必要な回転配向との方向を。それによって我々は簡単に方向を決定することはできません!?
ねえ〜私が読んで: ExifInterface exifInterface = new ExifInterface(filepath);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
...
复制代码
我々はすぐにあなたが出て内部の行き止まりに達している可能性があり、あなたがこのプロジェクトのコードを使用している場合は、読むためにこのコードを使用EXIFを読み取ることができないところemmmm ...これはです!
アプリのEXIFを見ることができる最初のダウンロードは、私が使用して写真のExifエディタ、それは次のように開きます。
Iボボかわいいですか?
図EXIFの一見が、表示する写真のEXIFエディタでプロジェクトのカメラは、マップの外に撮影し、すべてのEXIFデータが空になっているので、あなたが読むためのコードを使用する場合は、デフォルト値で埋めることだけ読んだことがありません。
何探る行く失った理由exifのコールバック内で)それを、私はそれがカレマのAPIの問題だと思ったが、onPictureTakenで(直接画像を保存し、EXIF問題は内部のコードを回転させることにある明らかに、存在して、あなたが推測することができているに変換際にビットマップ情報は、EXIF失われたいくつかの検査データの後に、それは本当です、。
Exif情報を失うことになる理由のExifは、何ですか?
そう画像を有する圧縮された画像ファイルのデータの記述から求めることができるExif2.2仕様:
そのような説明 事実 圧縮画像データとマーカコードから圧縮された画像ファイル、コードマーカデータのExifを含みます:。もちろん、クラスなどのビットマップ画像は、画像データのみを抽出含まれています。概要
写真はexifの失われたビットマップに変換するので、あなたは後に保存保存するために写真をアップし編集する必要があるときに、EXIF行くためにもう一度写真を変更します。
Exifのは、仕様書の2.2版があれば理解したいExif2.2ポータルが。
今、あなたはよく知っていることを、Exifのは、それを読んでください!
ExifInterface exifInterface = new ExifInterface(filepath);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
...
复制代码
私は~~~~↓を読みます
ショック!実際には期待と矛盾します。。これは、内部電話システムでは、このような差は、Androidの断片化を浮上している証明しました!キビ:フォト方向は、携帯電話の方向と一致し、正しく回転されない、Exifの90°。
VIVO:画像の向きは、携帯電話の方向と矛盾している右回転し、Exifの90°。
仕事は足踏み状態になりました。。ダニエルは唯一〜魚の弟の外に移動することができます
いくつかの問い合わせ後、コロンビアの魚は私の問題を解決するために彼のコードを表示 - 再びコロンビアの魚に感謝しますカメラの設定パラメータ
カメラ#パラメータこのクラスのと、私は学生がカメラに慣れ不慣れではないだろうと信じて、カメラのパラメータにアクセスし、設定するために使用することができます、プレビューサイズを取得フラッシュを設定し、フォーカスモード、など、この構成ではクラスによって規制されている、我々はしたいです補正方法は、ここに隠れてすることが判明しました!
public class IOrientationEventListener extends OrientationEventListener {
public IOrientationEventListener(Context context) {
super(context);
}
@Override
public void onOrientationChanged(int orientation) {
if (ORIENTATION_UNKNOWN == orientation) {
return;
}
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(defaultCameraId, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else {
rotation = (info.orientation + orientation) % 360;
}
if (null != mCamera) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setRotation(rotation);//关键代码
mCamera.setParameters(parameters);
}
}
}
复制代码
例を取得した後コールバック## SurfaceHolderにあるsurfaceCreated()とコールバック## SurfaceHolder surfaceDestroyedインスタンスで()呼び出し可能()および無効()をすることができるカメラの回転の問題を統一。
onOrientationChanged()コールバック頻繁なので、より最適化アプローチ魚のカメラは、捕捉ボタンを押した後に設定することができます。
これは、メーカーがデフォルトは断片化カメラの向きを設定することを意味する限り一定回転の値は、すべてのカメラ付き携帯電話の向きが統一されているように、回転の値を変更することによって求めることができます。
回転の問題を解決するために、これまでお使いのカメラをカスタマイズします。
高速回転の写真
大型車の上記の説明を通じて、賢い学生は、すでにプログラムの急速な回転と疑うこと - のExifの使用です。
因为照片本身是有设备生成的Exif的,里面含有标记照片方向的orientation,图片加载框架会通过读取orientation来对照片进行显示,也就是说,通过修改Exif里orientation的值,即可以达到旋转照片的效果!而且只需要操作一个小参数就能完成,瞬间完成,速度杠杠的!再也不怕旋转图片慢啦!
看一下Glide的处理: 对Exif解析确认图像方向
//默认的图片头解析器
public final class DefaultImageHeaderParser implements ImageHeaderParser {
...
private int getOrientation(Reader reader, ArrayPool byteArrayPool) throws IOException {
...
int exifSegmentLength = moveToExifSegmentAndGetLength(reader);
if (exifSegmentLength == -1) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to parse exif segment length, or exif segment not found");
}
return UNKNOWN_ORIENTATION;
}
byte[] exifData = byteArrayPool.get(exifSegmentLength, byte[].class);
try {
return parseExifSegment(reader, exifData, exifSegmentLength);
} finally {
byteArrayPool.put(exifData);
}
...
}
...
}
复制代码
逆时针方向旋转的代码:
ExifInterface exifInterface = new ExifInterface(currentPath);
// 获取图片的旋转信息
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
LogUtils.v("exif orientation:" + orientation);
//根据当前图片方向设置想要的图片方向
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90://正常角度
exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL+"");
break;
case ExifInterface.ORIENTATION_ROTATE_180:
exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_ROTATE_90+"");
break;
case ExifInterface.ORIENTATION_ROTATE_270:
exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_ROTATE_180+"");
break;
case ExifInterface.ORIENTATION_NORMAL:
exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_ROTATE_270+"");
break;
}
exifInterface.saveAttributes();
复制代码
使用注意: 这种方案只能用于具有Exif的照片,旋转之后的照片显示需要注意缓存问题,每次旋转之后要更新缓存以正确显示照片。
Glide在加载图片的时候直接通过signature()方法new ObjectKey传入文件的修改时间作缓存标记即可:
Glide.with(context)
.load(filePath)
.signature(new ObjectKey(file.lastModified())
.into(imageView);
复制代码
其他框架的话请自行查找啦~
结尾
终于写完了,要是觉得有用或者让你拓展了知识就点个赞以示支持呗~谢谢你的观看和学习!下回再见~
转载于:https://juejin.im/post/5cf76785f265da1b827a8a98