Android:复制位图

发布于 2024-10-25 08:36:31 字数 1086 浏览 1 评论 0原文

一个看似简单的问题,我有一个离屏位图,我对其执行一些转换(旋转、缩放等),并且我想在转换之前存储位图的副本,以便在我的视图的 中onDraw(),我可以将转换后的离屏位图和未转换位图的较小缩放版本显示为缩略图。

onDraw() 中写入离屏位图没有问题,但复制的“保留”位图也会被转换。这是我制作位图副本的代码,其中 mCanvas 是通过 mCanvas = new Canvas(mBitmap); 创建的:

mPreservedBitmap = Bitmap.createBitmap(mBitmap);

// save the canvas
mCanvas.save();

// do some rotations, scaling
mCanvas.rotate(rotation, px, py);
mCanvas.scale(scaleFactor, scaleFactor, scaleFocusX, scaleFocusY);

// draw the bitmaps to the screen
invalidate();

// restore the bitmap
mCanvas.restore();

在 onDraw() 中,我有:

// draw the off-screen bitmap to the on-screen bitmap
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

// draw the preserved image, scaling it to a thumbnail first
canvas.drawBitmap(
    Bitmap.createScaledBitmap(mPreservedBitmap, (int) thumbWidth, (int) thumbHeight, true), 
null, 
thumbnailRectF, 
thumbCanvasPaint);

缩略图被缩放到适当的大小,但是被缩小到缩略图大小的位图也被旋转和缩放,与 mBitmap 完全相同,这是我不想要的。我也尝试过 Bitmap.copy() 方法,但结果相同。有什么指示/帮助/建议吗?

谢谢,

保罗

A seemingly simple issue, I have an off-screen bitmap that I perform some transformations to (rotation, scaling, etc) and I'd like to store a copy of the bitmap prior to the transformations, such that in my View's onDraw(), I can display the transformed off-screen bitmap AND a smaller scaled version of the un-transformed bitmap as a thumbnail.

No problem writing the off-screen bitmap in onDraw(), but the copied 'preserved' bitmap is also being transformed. Here is the code where I am making the copy of the bitmap, where mCanvas was created via mCanvas = new Canvas(mBitmap);:

mPreservedBitmap = Bitmap.createBitmap(mBitmap);

// save the canvas
mCanvas.save();

// do some rotations, scaling
mCanvas.rotate(rotation, px, py);
mCanvas.scale(scaleFactor, scaleFactor, scaleFocusX, scaleFocusY);

// draw the bitmaps to the screen
invalidate();

// restore the bitmap
mCanvas.restore();

In onDraw(), I have:

// draw the off-screen bitmap to the on-screen bitmap
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

// draw the preserved image, scaling it to a thumbnail first
canvas.drawBitmap(
    Bitmap.createScaledBitmap(mPreservedBitmap, (int) thumbWidth, (int) thumbHeight, true), 
null, 
thumbnailRectF, 
thumbCanvasPaint);

The thumbnail gets scaled to the appropriate size, but the bitmap that is being scaled down to thumbnail size is also rotated and scaled the exact same as mBitmap, which I don't want. I've also tried the Bitmap.copy() method, but with the same results. Any pointers/assitance/advice?

Thanks,

Paul

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

记忆消瘦 2024-11-01 08:36:31

你做错了:) 首先,你永远不应该在字段中保留对 Canvas 的引用。无法保证两次不同的 onDraw() 调用中 Canvas 实例是相同的。第二个问题是如何应用转换。您应该在 onDraw() 中应用它们:

canvas.save();
canvas.rotate(rotation, px, py);
canvas.scale(scaleFactor, scaleFactor, scaleFocusX, scaleFocusY);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();

canvas.drawBitmap(
    Bitmap.createScaledBitmap(mPreservedBitmap, (int) thumbWidth, (int) thumbHeight, true), null, thumbnailRectF, thumbCanvasPaint);

invalidate() 不是同步操作,如果在 onDraw() 之外完成,您的 save()/restore() 不能保证正常工作。

另外,不要从 onDraw() 调用 createScaledBitmap(),它的开销非常大。

You are doing it wrong :) First of all you should never keep a reference to a Canvas in a field. There is no guarantee whatsoever that the Canvas instance will be the same in two different calls to onDraw(). Your second problem is how you apply the transformations. You should apply them in onDraw():

canvas.save();
canvas.rotate(rotation, px, py);
canvas.scale(scaleFactor, scaleFactor, scaleFocusX, scaleFocusY);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();

canvas.drawBitmap(
    Bitmap.createScaledBitmap(mPreservedBitmap, (int) thumbWidth, (int) thumbHeight, true), null, thumbnailRectF, thumbCanvasPaint);

invalidate() is not a synchronous operation, your save()/restore() has no guarantee to work if done outside of onDraw().

Also do not call createScaledBitmap() from onDraw(), it is extremely expensive.

伊面 2024-11-01 08:36:31

扩展我的评论:

Bitmap.createBitmap(Bitmap) 返回一个不可变的位图。文档实际上说它可能是相同的对象或使用相同的数据。
如果您确实想修改它,则必须创建一个可变位图,例如:

mPreservedBitmap = mBitmap;

// Create a new, empty bitmap with the original size.
// Since the image is going to be scaled, this might be to big or to small.
// Rotating might also require additional space (otherwise the corners will be cut off)
// Try calculating the proper size or play around with some other createBitmap Methods, just make sure to
// actually create a mutable bitmap, for example by using copy on an immutable bitmap.
mBitmap = Bitmap.createBitmap(mPreservedBitmap.getWidth(), mPreservedBitmap.getHeight(), mPreservedBitmap.getConfig());

mCanvas = new Canvas(mBitmap);

// do some rotations, scaling
mCanvas.rotate(rotation, px, py);
mCanvas.scale(scaleFactor, scaleFactor, scaleFocusX, scaleFocusY);

// draw the original image to the canvas, applying the matrix modifications
mCanvas.drawBitmap(mPreservedBitmap, 0, 0, null);

在 onDraw 中:

// draw the off-screen bitmap to the on-screen bitmap
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

// draw the preserved image, scaling it to a thumbnail
canvas.drawBitmap(mPreservedBitmap, null, thumbnailRectF, thumbCanvasPaint);

To expand on my comment:

Bitmap.createBitmap(Bitmap) returns an immutable bitmap. The documentation actually says that it might be the same object or use the same data.
You have to create a mutable bitmap, if you actually want to modify it, for example:

mPreservedBitmap = mBitmap;

// Create a new, empty bitmap with the original size.
// Since the image is going to be scaled, this might be to big or to small.
// Rotating might also require additional space (otherwise the corners will be cut off)
// Try calculating the proper size or play around with some other createBitmap Methods, just make sure to
// actually create a mutable bitmap, for example by using copy on an immutable bitmap.
mBitmap = Bitmap.createBitmap(mPreservedBitmap.getWidth(), mPreservedBitmap.getHeight(), mPreservedBitmap.getConfig());

mCanvas = new Canvas(mBitmap);

// do some rotations, scaling
mCanvas.rotate(rotation, px, py);
mCanvas.scale(scaleFactor, scaleFactor, scaleFocusX, scaleFocusY);

// draw the original image to the canvas, applying the matrix modifications
mCanvas.drawBitmap(mPreservedBitmap, 0, 0, null);

And in onDraw:

// draw the off-screen bitmap to the on-screen bitmap
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

// draw the preserved image, scaling it to a thumbnail
canvas.drawBitmap(mPreservedBitmap, null, thumbnailRectF, thumbCanvasPaint);
以可爱出名 2024-11-01 08:36:31

我的最终解决方案是在缩放画布 Bitmap 之前通过以下方式生成画布的副本:

mPreservedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), null, true);

然后,当缩放 Canvas 和主位图时,我可以绘制通过以下方式将未缩放的“保留”Bitmap 转换为 onDraw() 中的 Canvas

canvas.drawBitmap(mPreservedBitmap, null, thumbnailRectF, thumbCanvasPaint);

根据上面 Romain 的评论,我缩放了保留的 位图离屏以提高onDraw()中的性能。

My final solution to this was to generate a copy of the canvas Bitmap PRIOR to it being scaled via:

mPreservedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), null, true);

Then, when the Canvas and the primary Bitmap is scaled, I can draw the non-scaled 'preserved' Bitmap to the Canvas in onDraw() via:

canvas.drawBitmap(mPreservedBitmap, null, thumbnailRectF, thumbCanvasPaint);

Per Romain's comments above, I scale the preserved Bitmap off-screen to improve performance in onDraw().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文