2011-03-23 5 views
2

Un problème apparemment simple, j'ai un bitmap hors écran que j'effectue des transformations (rotation, mise à l'échelle, etc) et je voudrais stocker une copie de l'image avant les transformations, de sorte que dans onDraw() de ma vue, je peux afficher le bitmap hors écran transformé ET une version plus petite mise à l'échelle du bitmap non transformé comme une vignette.Android: Copie d'un bitmap

Aucun problème lors de l'écriture du bitmap hors écran dans onDraw(), mais le bitmap «préservé» copié est également en cours de transformation. Voici le code où je fais la copie du bitmap, où mCanvas a été créé par 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(); 

En onDraw(), j'ai:

// 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); 

La vignette se redimensionnée à la taille appropriée, mais le bitmap qui est réduit à la taille des vignettes est également pivoté et mis à l'échelle exactement comme mBitmap, ce que je ne veux pas. J'ai également essayé la méthode Bitmap.copy(), mais avec les mêmes résultats. N'importe quel pointeur/assitance/conseil?

Merci,

Paul

+0

Y a-t-il autre chose que vous faites avec mCanvas à partir du premier extrait?Il ne semble pas réellement faire quoi que ce soit (la rotation etc. n'affecte que les opérations futures, pas l'image elle-même). Et pourquoi essayez-vous de copier le bitmap dans onDraw? En modifiant la matrice de la toile de manière appropriée, vous devriez être en mesure de mettre à l'échelle la vignette à la volée. –

+0

J'utilise mCanvas à d'autres points du code pour ajouter des formes terminées que l'utilisateur a dessinées dans le bitmap hors écran. Je pourrais en effet déplacer le code createScaledBitmap hors de onDraw, je l'avais juste là pour tester la copie/mise à l'échelle. –

Répondre

1

Ma solution finale à c'était de générer une copie du Bitmap toile avant d'être mis à l'échelle par:

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

Ensuite, lorsque le Canvas et le premier bitmap est mis à l'échelle, je peux tirer la non-mise à l'échelle « pres dé- laissées » Bitmap au Canvas en onDraw() via:

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

commentaires de Per Romain ci-dessus, je l'échelle préservée Bitmap hors écran pour améliorer les performances dans onDraw().

3

Vous le faites mal :) Tout d'abord, vous devez jamais conserver une référence à une toile dans un champ. Il n'y a aucune garantie que l'instance de Canvas soit la même dans deux appels différents à onDraw(). Votre deuxième problème est de savoir comment vous appliquez les transformations. Vous devriez les appliquer dans 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() n'est pas une opération synchrone, votre sauvegarde()/restauration() n'a aucune garantie de travailler si elle est faite en dehors de onDraw().

Également faire pas appel createScaledBitmap() à partir de onDraw(), il est extrêmement coûteux.

+0

Merci Romain. Je répondrai en deux commentaires séparés. Si ce n'est pas la référence au canevas, qui est utilisée pour accéder au mBitmap hors écran, comment puis-je écrire plusieurs fois sur le bitmap? C'est un programme de dessin qui valide les formes complétées sur le bitmap hors écran lorsque l'utilisateur les termine; Lorsque l'utilisateur dessine une forme en cours, j'appelle onDraw(), et une fois la forme terminée, elle est ajoutée cumulativement à mBitmap via mCanvas. Dois-je créer de nouvelles références Canvas chaque fois que je souhaite accéder au mBitmap 'Canvas canvas = new Canvas (mBitmap);'? –

+0

En termes d'exécution des rotations et de mise à l'échelle dans onDraw(), je l'avais initialement configuré de cette façon, mais comme j'appelle onDraw lorsque l'utilisateur dessine la forme courante à l'écran, les choses étaient très décalées. mettre à l'échelle le bitmap hors écran à la volée pour n paires x/y possibles. Je l'ai configuré de sorte que lorsque l'utilisateur est mise à l'échelle, la totalité de l'image bitmap hors écran est redessinée en dehors de l'écran, puis flashée sur la toile dans onDraw(). Toutefois, si l'utilisateur a terminé la mise à l'échelle et dessine à l'échelle, j'appelle simplement onDraw et j'utilise le bitmap hors écran déjà mis à l'échelle. –

+0

Comme autre suivi, j'ai changé le code pour que la rotation et la mise à l'échelle se passent dans onDraw() ... et la performance est assez brutale. Lorsque l'utilisateur est dans un état dans lequel le canevas est pivoté et qu'il est mis à l'échelle, alors qu'il dessine et onDraw() est appelé pour montrer sa progression, le décalage/performance est inutilisable. J'ai dû louper quelque chose. –

1

développiez mon commentaire:

Bitmap.createBitmap(Bitmap) renvoie une image bitmap immuable. La documentation indique en fait qu'il pourrait s'agir du même objet ou utiliser les mêmes données. Vous devez créer un bitmap mutable, si vous voulez vraiment le modifier, par exemple:

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); 

Et 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); 
+0

Hmm, essayé ceci, mais le mPreservedBitmap est en train d'être mis à la version mise à l'échelle de mBitmap ... –