我正在尝试拍摄从相机捕获的图像并在其上放置相框或叠加层。相框基本上是一个 png 图像,放置在一个ImageView
也FrameLayout
包含 SurfaceView 的内部。问题是我必须缩放包含照片图像和相框图像的视图的一个或两个结果位图,以便将叠加层放置在捕获的照片图像上的正确位置。但是由于它们具有不同的纵横比,我不知道如何在不使照片或叠加层失真的情况下做到这一点。这是我处理位图操作的代码。此外,由于位图的巨大尺寸,我有时会遇到 OutofMemory 异常。我试着用MappedByteBuffer
但也无法让它正常工作......叹息。无论如何,非常感谢任何关于我做错了什么的建议或显示更好方法的代码示例!
private void saveTempPhoto(byte[] data) {
// Need to flip back the photo frame on front facing camera.
if (this.isCameraFront)
this.flipPhotoFrame();
findViewById(R.id.close_button).setVisibility(View.INVISIBLE);
findViewById(R.id.flash_button).setVisibility(View.INVISIBLE);
findViewById(R.id.focus_button).setVisibility(View.INVISIBLE);
findViewById(R.id.take_photo).setVisibility(View.INVISIBLE);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[32 * 1024];
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inJustDecodeBounds = true;
Bitmap bitmapPhoto = null;
Bitmap bitmapPhotoFrame = null;
Bitmap bitmapCanvas = null;
View view = findViewById(R.id.top_photo_frame); //view containing the photoframe
try {
int photoFrameWidth = view.getWidth();
int photoFrameHeight = view.getHeight();
BitmapFactory.decodeByteArray(data, 0, data.length, options);
if (orientation == 90 || orientation == 270) {
//Swap height and width
int temp = options.outWidth;
options.outWidth = options.outHeight;
options.outHeight = temp;
}
// Calculate the best sample size to use based on the ratio of the captured image to the photoframe.
// This is done to prevent OutofMemoryExceptions from occurring, as the bitmap allocations can use up a lot of heap space.
float ratioWidth = (float)options.outWidth / (float)photoFrameWidth;
float ratioHeight = (float)options.outHeight / (float)photoFrameHeight;
float ratio = Math.min(ratioWidth, ratioHeight);
if (ratioWidth > 1 || ratioHeight > 1) {
double power = Math.log(ratio) / Math.log(2);
options.inSampleSize = (int) Math.pow(2, Math.round(power));
}
options.inJustDecodeBounds = false;
Bitmap bitmapPhotoPreRotate = BitmapFactory.decodeByteArray(data, 0, data.length, options);
int postRotation = isCameraFront ? -orientation : orientation;
if (orientation != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(postRotation);
bitmapPhoto = Bitmap.createBitmap(bitmapPhotoPreRotate, 0, 0, bitmapPhotoPreRotate.getWidth(), bitmapPhotoPreRotate.getHeight(), matrix, true);
bitmapPhotoPreRotate.recycle();
}
else
bitmapPhoto = bitmapPhotoPreRotate;
Log.d("PhotoFrameActivity", String.format("Photo bitmap has width %d and height %d", bitmapPhoto.getWidth(), bitmapPhoto.getHeight()));
Log.d("PhotoFrameActivity", String.format("PhotoFrame bitmap has width %d and height %d", view.getWidth(), view.getHeight()));
int photoWidth = bitmapPhoto.getWidth();
int photoHeight = bitmapPhoto.getHeight();
Bitmap.Config photoConfig = bitmapPhoto.getConfig();
bitmapCanvas = Bitmap.createBitmap(photoWidth,
photoHeight, photoConfig);
if (bitmapCanvas != null) {
Canvas canvas = new Canvas(bitmapCanvas);
canvas.drawBitmap(bitmapPhoto, new Matrix(), null);
bitmapPhoto.recycle();
bitmapPhoto = null;
System.gc(); //Try to force GC here to free up some memory
bitmapPhotoFrame = Bitmap.createScaledBitmap(
this.loadBitmapFromView(view),
photoWidth,
photoHeight,
true);
canvas.drawBitmap(bitmapPhotoFrame, 0, 0, null);
bitmapPhotoFrame.recycle();
Log.d("PhotoFrameActivity", String.format("Combined bitmap has width %d and height %d", bitmapCanvas.getWidth(), bitmapCanvas.getHeight()));
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmapCanvas.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] jpegWithPhotoFrame = stream.toByteArray();
try {
createPhotoFile();
FileOutputStream fos = new FileOutputStream(photoFile);
fos.write(jpegWithPhotoFrame);
fos.close();
Log.d("PhotoFrameActivity", String.format("Image file saved to %s", photoFile.getPath()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (bitmapCanvas != null)
bitmapCanvas.recycle();
if (bitmapPhoto != null)
bitmapPhoto.recycle();
if (bitmapPhotoFrame != null)
bitmapPhotoFrame.recycle();
}
}
catch (OutOfMemoryError e) {
// Put up out of memory alert
AlertDialog dialogError = new AlertDialog.Builder(this).create();
dialogError.setButton(DialogInterface.BUTTON_POSITIVE,"OK",
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
finish();
}
}
);
dialogError.setMessage("Out of memory!");
dialogError.show();
}
catch (Exception e) {
e.printStackTrace();
}
}