Ich habe eine große Bitmap (sagen wir 3888x2592) in einer Datei. Jetzt möchte ich die Größe des Bitmaps auf 800x533 ändern und es in einer anderen Datei speichern. Normalerweise würde ich das Bitmap skalieren, indem ich die Bitmap.createBitmap
-Methode aufrufe. Es wird jedoch eine Quellbitmap als erstes Argument benötigt, die ich beim Laden nicht angeben kann Das Originalbild in ein Bitmap-Objekt würde natürlich den Speicher überschreiten (siehe hier zum Beispiel).
Ich kann die Bitmap auch nicht lesen, zum Beispiel mit BitmapFactory.decodeFile(file, options)
und einem BitmapFactory.Options.inSampleSize
, da ich sie auf eine genaue Breite und Höhe skalieren möchte. Die Verwendung von inSampleSize
würde die Bitmap auf 972x648 (bei Verwendung von inSampleSize=4
) oder auf 778x518 (bei Verwendung von inSampleSize=5
, was nicht einmal eine Potenz von 2 ist) ändern.
Ich möchte auch vermeiden, das Bild mit inSampleSize mit beispielsweise 972x648 in einem ersten Schritt zu lesen und dann in einem zweiten Schritt genau auf 800x533 zu skalieren, da die Qualität im Vergleich zu einer direkten Größenänderung des Originalbilds schlecht wäre.
Um meine Frage zusammenzufassen: Gibt es eine Möglichkeit, eine große Image-Datei mit 10 MP oder mehr zu lesen und in einer neuen Image-Datei zu speichern, deren Größe auf eine bestimmte neue Breite und Höhe geändert wird, ohne eine OutOfMemory-Ausnahme zu erhalten?
Ich habe auch BitmapFactory.decodeFile(file, options)
ausprobiert und die Werte für Options.outHeight und Options.outWidth manuell auf 800 und 533 gesetzt, dies funktioniert jedoch nicht.
Nein. Ich würde mich sehr freuen, wenn mich jemand korrigiert, aber ich habe den Ansatz von load/size akzeptiert, den Sie als Kompromiss versucht haben.
Hier sind die Schritte für alle, die surfen:
inSampleSize
, das immer noch ein Bild ergibt, das größer als Ihr Ziel ist.BitmapFactory.decodeFile(file, options)
und übergeben Sie inSampleSize als Option.Bitmap.createScaledBitmap()
auf die gewünschten Abmessungen.Justin Antwort in Code übersetzt (funktioniert perfekt für mich):
private Bitmap getBitmap(String path) {
Uri uri = getImageUri(path);
InputStream in = null;
try {
final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
in = mContentResolver.openInputStream(uri);
// Decode image size
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
in.close();
int scale = 1;
while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) >
IMAGE_MAX_SIZE) {
scale++;
}
Log.d(TAG, "scale = " + scale + ", orig-width: " + options.outWidth + ",
orig-height: " + options.outHeight);
Bitmap resultBitmap = null;
in = mContentResolver.openInputStream(uri);
if (scale > 1) {
scale--;
// scale to max possible inSampleSize that still yields an image
// larger than target
options = new BitmapFactory.Options();
options.inSampleSize = scale;
resultBitmap = BitmapFactory.decodeStream(in, null, options);
// resize to desired dimensions
int height = resultBitmap.getHeight();
int width = resultBitmap.getWidth();
Log.d(TAG, "1th scale operation dimenions - width: " + width + ",
height: " + height);
double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(resultBitmap, (int) x,
(int) y, true);
resultBitmap.recycle();
resultBitmap = scaledBitmap;
System.gc();
} else {
resultBitmap = BitmapFactory.decodeStream(in);
}
in.close();
Log.d(TAG, "bitmap size - width: " +resultBitmap.getWidth() + ", height: " +
resultBitmap.getHeight());
return resultBitmap;
} catch (IOException e) {
Log.e(TAG, e.getMessage(),e);
return null;
}
Dies ist "Mojo Risins und" Ofirs Lösungen "kombiniert". Dadurch erhalten Sie ein proportional angepasstes Bild mit den Grenzen von maximaler Breite und maximaler Höhe.
Für mich hat es eine gute Leistung bei 5 MegaPixel-Bildern und darunter ergeben.
try
{
int inWidth = 0;
int inHeight = 0;
InputStream in = new FileInputStream(pathOfInputImage);
// decode image size (decode metadata only, not the whole image)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
in.close();
in = null;
// save width and height
inWidth = options.outWidth;
inHeight = options.outHeight;
// decode full image pre-resized
in = new FileInputStream(pathOfInputImage);
options = new BitmapFactory.Options();
// calc rought re-size (this is no exact resize)
options.inSampleSize = Math.max(inWidth/dstWidth, inHeight/dstHeight);
// decode full image
Bitmap roughBitmap = BitmapFactory.decodeStream(in, null, options);
// calc exact destination size
Matrix m = new Matrix();
RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
RectF outRect = new RectF(0, 0, dstWidth, dstHeight);
m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
float[] values = new float[9];
m.getValues(values);
// resize bitmap
Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);
// save image
try
{
FileOutputStream out = new FileOutputStream(pathOfOutputImage);
resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
}
catch (Exception e)
{
Log.e("Image", e.getMessage(), e);
}
}
catch (IOException e)
{
Log.e("Image", e.getMessage(), e);
}
Warum nicht die API verwenden?
int h = 48; // height in pixels
int w = 48; // width in pixels
Bitmap scaled = Bitmap.createScaledBitmap(largeBitmap, w, h, true);
Die andere hervorragende Antwort, die ich bisher gesehen habe, ist der beste Code, den ich bisher dafür gesehen habe, in der Dokumentation des Tools zum Fotografieren.
Siehe den Abschnitt "Decodieren eines skalierten Bildes".
http://developer.Android.com/training/camera/photobasics.html
Die Lösung, die es vorschlägt, ist eine Größenanpassung und dann eine Skalierungslösung wie die anderen hier, aber es ist ziemlich ordentlich.
Ich habe den folgenden Code aus praktischen Gründen als Ready-to-Go-Funktion kopiert.
private void setPic(String imagePath, ImageView destination) {
int targetW = destination.getWidth();
int targetH = destination.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
destination.setImageBitmap(bitmap);
}
Nach dem Lesen dieser Antworten und Android-Dokumentation hier der Code zum Ändern der Bitmap-Größe, ohne sie in den Speicher zu laden:
public Bitmap getResizedBitmap(int targetW, int targetH, String imagePath) {
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
//inJustDecodeBounds = true <-- will not load the bitmap into memory
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
return(bitmap);
}
Wenn ich große Bitmaps habe und sie in ihrer Größe decodieren möchte, verwende ich Folgendes
BitmapFactory.Options options = new BitmapFactory.Options();
InputStream is = null;
is = new FileInputStream(path_to_file);
BitmapFactory.decodeStream(is,null,options);
is.close();
is = new FileInputStream(path_to_file);
// here w and h are the desired width and height
options.inSampleSize = Math.max(options.outWidth/w, options.outHeight/h);
// bitmap is the resized bitmap
Bitmap bitmap = BitmapFactory.decodeStream(is,null,options);
Dies kann für andere Personen nützlich sein, die sich diese Frage ansehen. Ich habe den Code von Justin neu geschrieben, damit die Methode auch das gewünschte Zielgrößenobjekt erhalten kann. Dies funktioniert sehr gut bei der Verwendung von Canvas. Alles Gute sollte an Justin für seinen großartigen anfänglichen Code gehen.
private Bitmap getBitmap(int path, Canvas canvas) {
Resources resource = null;
try {
final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
resource = getResources();
// Decode image size
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resource, path, options);
int scale = 1;
while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) >
IMAGE_MAX_SIZE) {
scale++;
}
Log.d("TAG", "scale = " + scale + ", orig-width: " + options.outWidth + ", orig-height: " + options.outHeight);
Bitmap pic = null;
if (scale > 1) {
scale--;
// scale to max possible inSampleSize that still yields an image
// larger than target
options = new BitmapFactory.Options();
options.inSampleSize = scale;
pic = BitmapFactory.decodeResource(resource, path, options);
// resize to desired dimensions
int height = canvas.getHeight();
int width = canvas.getWidth();
Log.d("TAG", "1th scale operation dimenions - width: " + width + ", height: " + height);
double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(pic, (int) x, (int) y, true);
pic.recycle();
pic = scaledBitmap;
System.gc();
} else {
pic = BitmapFactory.decodeResource(resource, path);
}
Log.d("TAG", "bitmap size - width: " +pic.getWidth() + ", height: " + pic.getHeight());
return pic;
} catch (Exception e) {
Log.e("TAG", e.getMessage(),e);
return null;
}
}
Der Code von Justin ist sehr effektiv, um den Aufwand bei der Arbeit mit großen Bitmaps zu reduzieren.
Ich weiß nicht, ob meine Lösung die beste Methode ist, aber ich habe das Laden einer Bitmap mit der gewünschten Skalierung mithilfe der Optionen inDensity
und inTargetDensity
erreicht. inDensity
ist anfangs 0
, wenn keine zeichnungsfähige Ressource geladen wird. Dieser Ansatz dient dem Laden von Nicht-Ressourcen-Images.
Die Variablen imageUri
, maxImageSideLength
und context
sind Parameter meiner Methode. Ich habe nur die Methodenimplementierung ohne die Umhüllung AsyncTask zur Verdeutlichung bereitgestellt.
ContentResolver resolver = context.getContentResolver();
InputStream is;
try {
is = resolver.openInputStream(imageUri);
} catch (FileNotFoundException e) {
Log.e(TAG, "Image not found.", e);
return null;
}
Options opts = new Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, opts);
// scale the image
float maxSideLength = maxImageSideLength;
float scaleFactor = Math.min(maxSideLength / opts.outWidth, maxSideLength / opts.outHeight);
// do not upscale!
if (scaleFactor < 1) {
opts.inDensity = 10000;
opts.inTargetDensity = (int) ((float) opts.inDensity * scaleFactor);
}
opts.inJustDecodeBounds = false;
try {
is.close();
} catch (IOException e) {
// ignore
}
try {
is = resolver.openInputStream(imageUri);
} catch (FileNotFoundException e) {
Log.e(TAG, "Image not found.", e);
return null;
}
Bitmap bitmap = BitmapFactory.decodeStream(is, null, opts);
try {
is.close();
} catch (IOException e) {
// ignore
}
return bitmap;
Unter Berücksichtigung der Tatsache, dass Sie die Größe exakt anpassen möchten und so viel Qualität wie nötig beibehalten möchten, sollten Sie dies versuchen.
Motivation: Durch die Skalierung mit mehreren Schritten können Sie eine bessere Bildqualität erzielen. Es gibt jedoch keine Garantie dafür, dass es besser funktioniert als mit der Verwendung von high inSampleSize. Eigentlich denke ich, dass Sie auch inSampleSize wie 5 (nicht 2) verwenden können, um eine direkte Skalierung in einem Vorgang durchzuführen. Oder verwenden Sie einfach 4 und dann können Sie dieses Bild in der Benutzeroberfläche verwenden. Wenn Sie es an den Server senden, können Sie es auf die serverseitige Größe genau skalieren, um erweiterte Skalierungstechniken verwenden zu können.
Hinweise: Wenn die in Schritt 3 geladene Bitmap mindestens viermal so groß ist (also 4 * targetWidth <width), können Sie wahrscheinlich mehrere Größenanpassungen verwenden, um eine bessere Qualität zu erzielen. zumindest funktioniert das in generischem Java. In Android haben Sie nicht die Möglichkeit, die für die Skalierung verwendete Interpolation anzugeben http://today.Java.net/pub/a/today/2007/ 04/03/bedrohlich-von-image-getscaledinstance.html
Der obige Code wurde etwas sauberer. InputStreams haben endlich eine enge Umhüllung, um sicherzustellen, dass sie auch geschlossen werden:
*Hinweis
Eingabe: InputStream ist, int w, int h
Ausgabe: Bitmap
try
{
final int inWidth;
final int inHeight;
final File tempFile = new File(temp, System.currentTimeMillis() + is.toString() + ".temp");
{
final FileOutputStream tempOut = new FileOutputStream(tempFile);
StreamUtil.copyTo(is, tempOut);
tempOut.close();
}
{
final InputStream in = new FileInputStream(tempFile);
final BitmapFactory.Options options = new BitmapFactory.Options();
try {
// decode image size (decode metadata only, not the whole image)
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
}
finally {
in.close();
}
// save width and height
inWidth = options.outWidth;
inHeight = options.outHeight;
}
final Bitmap roughBitmap;
{
// decode full image pre-resized
final InputStream in = new FileInputStream(tempFile);
try {
final BitmapFactory.Options options = new BitmapFactory.Options();
// calc rought re-size (this is no exact resize)
options.inSampleSize = Math.max(inWidth/w, inHeight/h);
// decode full image
roughBitmap = BitmapFactory.decodeStream(in, null, options);
}
finally {
in.close();
}
tempFile.delete();
}
float[] values = new float[9];
{
// calc exact destination size
Matrix m = new Matrix();
RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
RectF outRect = new RectF(0, 0, w, h);
m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
m.getValues(values);
}
// resize bitmap
final Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);
return resizedBitmap;
}
catch (IOException e) {
logger.error("Error:" , e);
throw new ResourceException("could not create bitmap");
}
Ich habe Code wie folgt verwendet:
String filePath=Environment.getExternalStorageDirectory()+"/test_image.jpg";
BitmapFactory.Options options=new BitmapFactory.Options();
InputStream is=new FileInputStream(filePath);
BitmapFactory.decodeStream(is, null, options);
is.close();
is=new FileInputStream(filePath);
// here w and h are the desired width and height
options.inSampleSize=Math.max(options.outWidth/460, options.outHeight/288); //Max 460 x 288 is my desired...
// bmp is the resized bitmap
Bitmap bmp=BitmapFactory.decodeStream(is, null, options);
is.close();
Log.d(Constants.TAG, "Scaled bitmap bytes, "+bmp.getRowBytes()+", width:"+bmp.getWidth()+", height:"+bmp.getHeight());
Ich habe versucht, das Originalbild ist 1230 x 1230, und die Bitmap sagt, es sei 330 x 330.
Wenn ich 2590 x 3849 ausprobiert habe, bekomme ich OutOfMemoryError.
Ich habe es verfolgt, es wirft immer noch OutOfMemoryError in der Zeile "BitmapFactory.decodeStream (is, null, options);".
Hier ist ein Artikel, der einen anderen Ansatz zur Größenänderung verwendet. Es wird versuchen, die größtmögliche Bitmap auf der Grundlage des verfügbaren Arbeitsspeichers in den Speicher zu laden, und dann die Transformationen ausführen.
http://bricolsoftconsulting.com/2012/12/07/handling-large-images-on-Android/
Um das Bild auf die "richtige" Weise zu skalieren, ohne Pixel zu überspringen, müssen Sie den Bilddecoder einhaken, um die Downsampling-Reihe zeilenweise durchzuführen. Android (und die dazugehörige Skia-Bibliothek) bietet keine solchen Haken, so dass Sie Ihre eigenen Rollen haben müssen. Angenommen, Sie sprechen von JPEG-Bildern, wäre es am besten, wenn Sie libjpeg direkt in C verwenden.
In Anbetracht der Komplexität ist die Verwendung der zweistufigen Subsample-Then-Rescale-Methode wahrscheinlich am besten für Apps mit Bildvorschau-Typ.
Wenn Sie unbedingt die Größe eines Schritts ändern möchten, können Sie wahrscheinlich die gesamte Bitmap laden, wennAndroid:largeHeap = true, aber wie Sie sehen, ist dies nicht wirklich ratsam.
Von docs: Android: largeHeap Gibt an, ob die Prozesse Ihrer Anwendung mit einem großen Dalvik-Heap erstellt werden sollen. Dies gilt für alle Prozesse, die für die Anwendung erstellt wurden. Es gilt nur für die erste Anwendung, die in einen Prozess geladen wird. Wenn Sie eine gemeinsam genutzte Benutzer-ID verwenden, um mehreren Anwendungen die Verwendung eines Prozesses zu gestatten, müssen sie alle diese Option konsequent verwenden, da sie sonst zu unvorhersehbaren Ergebnissen führen. Die meisten Apps sollten dies nicht benötigen und sollten sich stattdessen auf die Reduzierung des Gesamtspeichers konzentrieren Verwendung für verbesserte Leistung. Die Aktivierung dieser Option garantiert auch keine feste Erhöhung des verfügbaren Arbeitsspeichers, da einige Geräte durch ihren insgesamt verfügbaren Arbeitsspeicher eingeschränkt werden.
Das hat bei mir funktioniert. Die Funktion ruft einen Pfad zu einer Datei auf der SD-Karte ab und gibt eine Bitmap in der maximal darstellbaren Größe zurück. Der Code stammt von Ofir mit einigen Änderungen, z. B. einer Image-Datei auf SD, statt einer Ressource Objekt anzeigen.
private Bitmap makeBitmap(String path) {
try {
final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
//resource = getResources();
// Decode image size
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
int scale = 1;
while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) >
IMAGE_MAX_SIZE) {
scale++;
}
Log.d("TAG", "scale = " + scale + ", orig-width: " + options.outWidth + ", orig-height: " + options.outHeight);
Bitmap pic = null;
if (scale > 1) {
scale--;
// scale to max possible inSampleSize that still yields an image
// larger than target
options = new BitmapFactory.Options();
options.inSampleSize = scale;
pic = BitmapFactory.decodeFile(path, options);
// resize to desired dimensions
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.y;
int height = size.x;
//int height = imageView.getHeight();
//int width = imageView.getWidth();
Log.d("TAG", "1th scale operation dimenions - width: " + width + ", height: " + height);
double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(pic, (int) x, (int) y, true);
pic.recycle();
pic = scaledBitmap;
System.gc();
} else {
pic = BitmapFactory.decodeFile(path);
}
Log.d("TAG", "bitmap size - width: " +pic.getWidth() + ", height: " + pic.getHeight());
return pic;
} catch (Exception e) {
Log.e("TAG", e.getMessage(),e);
return null;
}
}
Ich verwende Integer.numberOfLeadingZeros
, um die beste Probengröße und bessere Leistung zu berechnen.
Vollständiger Code in Kotlin:
@Throws(IOException::class)
fun File.decodeBitmap(options: BitmapFactory.Options): Bitmap? {
return inputStream().use {
BitmapFactory.decodeStream(it, null, options)
}
}
@Throws(IOException::class)
fun File.decodeBitmapAtLeast(
@androidx.annotation.IntRange(from = 1) width: Int,
@androidx.annotation.IntRange(from = 1) height: Int
): Bitmap? {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
decodeBitmap(options)
val ow = options.outWidth
val oh = options.outHeight
if (ow == -1 || oh == -1) return null
val w = ow / width
val h = oh / height
if (w > 1 && h > 1) {
val p = 31 - maxOf(Integer.numberOfLeadingZeros(w), Integer.numberOfLeadingZeros(h))
options.inSampleSize = 1 shl maxOf(0, p)
}
options.inJustDecodeBounds = false
return decodeBitmap(options)
}
Hier ist der Code, den ich verwende, der keine Probleme mit der Dekodierung großer Bilder im Speicher von Android hat. Ich konnte Bilder größer als 20 MB decodieren, solange meine Eingabeparameter bei 1024 x 1024 liegen. Sie können die zurückgegebene Bitmap in einer anderen Datei speichern. Unter dieser Methode befindet sich eine weitere Methode, mit der ich auch Bilder auf eine neue Bitmap skalieren kann. Fühlen Sie sich frei, diesen Code nach Belieben zu verwenden.
/*****************************************************************************
* public decode - decode the image into a Bitmap
*
* @param xyDimension
* - The max XY Dimension before the image is scaled down - XY =
* 1080x1080 and Image = 2000x2000 image will be scaled down to a
* value equal or less then set value.
* @param bitmapConfig
* - Bitmap.Config Valid values = ( Bitmap.Config.ARGB_4444,
* Bitmap.Config.RGB_565, Bitmap.Config.ARGB_8888 )
*
* @return Bitmap - Image - a value of "null" if there is an issue decoding
* image dimension
*
* @throws FileNotFoundException
* - If the image has been removed while this operation is
* taking place
*/
public Bitmap decode( int xyDimension, Bitmap.Config bitmapConfig ) throws FileNotFoundException
{
// The Bitmap to return given a Uri to a file
Bitmap bitmap = null;
File file = null;
FileInputStream fis = null;
InputStream in = null;
// Try to decode the Uri
try
{
// Initialize scale to no real scaling factor
double scale = 1;
// Get FileInputStream to get a FileDescriptor
file = new File( this.imageUri.getPath() );
fis = new FileInputStream( file );
FileDescriptor fd = fis.getFD();
// Get a BitmapFactory Options object
BitmapFactory.Options o = new BitmapFactory.Options();
// Decode only the image size
o.inJustDecodeBounds = true;
o.inPreferredConfig = bitmapConfig;
// Decode to get Width & Height of image only
BitmapFactory.decodeFileDescriptor( fd, null, o );
BitmapFactory.decodeStream( null );
if( o.outHeight > xyDimension || o.outWidth > xyDimension )
{
// Change the scale if the image is larger then desired image
// max size
scale = Math.pow( 2, (int) Math.round( Math.log( xyDimension / (double) Math.max( o.outHeight, o.outWidth ) ) / Math.log( 0.5 ) ) );
}
// Decode with inSampleSize scale will either be 1 or calculated value
o.inJustDecodeBounds = false;
o.inSampleSize = (int) scale;
// Decode the Uri for real with the inSampleSize
in = new BufferedInputStream( fis );
bitmap = BitmapFactory.decodeStream( in, null, o );
}
catch( OutOfMemoryError e )
{
Log.e( DEBUG_TAG, "decode : OutOfMemoryError" );
e.printStackTrace();
}
catch( NullPointerException e )
{
Log.e( DEBUG_TAG, "decode : NullPointerException" );
e.printStackTrace();
}
catch( RuntimeException e )
{
Log.e( DEBUG_TAG, "decode : RuntimeException" );
e.printStackTrace();
}
catch( FileNotFoundException e )
{
Log.e( DEBUG_TAG, "decode : FileNotFoundException" );
e.printStackTrace();
}
catch( IOException e )
{
Log.e( DEBUG_TAG, "decode : IOException" );
e.printStackTrace();
}
// Save memory
file = null;
fis = null;
in = null;
return bitmap;
} // decode
ANMERKUNG: Methoden haben nichts miteinander zu tun, es sei denn, die createScaledBitmap-Methode ruft die decodierte Methode auf. Die Breite und Höhe der Notiz kann vom Originalbild abweichen.
/*****************************************************************************
* public createScaledBitmap - Creates a new bitmap, scaled from an existing
* bitmap.
*
* @param dstWidth
* - Scale the width to this dimension
* @param dstHeight
* - Scale the height to this dimension
* @param xyDimension
* - The max XY Dimension before the original image is scaled
* down - XY = 1080x1080 and Image = 2000x2000 image will be
* scaled down to a value equal or less then set value.
* @param bitmapConfig
* - Bitmap.Config Valid values = ( Bitmap.Config.ARGB_4444,
* Bitmap.Config.RGB_565, Bitmap.Config.ARGB_8888 )
*
* @return Bitmap - Image scaled - a value of "null" if there is an issue
*
*/
public Bitmap createScaledBitmap( int dstWidth, int dstHeight, int xyDimension, Bitmap.Config bitmapConfig )
{
Bitmap scaledBitmap = null;
try
{
Bitmap bitmap = this.decode( xyDimension, bitmapConfig );
// Create an empty Bitmap which will contain the new scaled bitmap
// This scaled bitmap should be the size we want to scale the
// original bitmap too
scaledBitmap = Bitmap.createBitmap( dstWidth, dstHeight, bitmapConfig );
float ratioX = dstWidth / (float) bitmap.getWidth();
float ratioY = dstHeight / (float) bitmap.getHeight();
float middleX = dstWidth / 2.0f;
float middleY = dstHeight / 2.0f;
// Used to for scaling the image
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale( ratioX, ratioY, middleX, middleY );
// Used to do the work of scaling
Canvas canvas = new Canvas( scaledBitmap );
canvas.setMatrix( scaleMatrix );
canvas.drawBitmap( bitmap, middleX - bitmap.getWidth() / 2, middleY - bitmap.getHeight() / 2, new Paint( Paint.FILTER_BITMAP_FLAG ) );
}
catch( IllegalArgumentException e )
{
Log.e( DEBUG_TAG, "createScaledBitmap : IllegalArgumentException" );
e.printStackTrace();
}
catch( NullPointerException e )
{
Log.e( DEBUG_TAG, "createScaledBitmap : NullPointerException" );
e.printStackTrace();
}
catch( FileNotFoundException e )
{
Log.e( DEBUG_TAG, "createScaledBitmap : FileNotFoundException" );
e.printStackTrace();
}
return scaledBitmap;
} // End createScaledBitmap
Bitmap yourBitmap;
Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true);
oder:
resized = Bitmap.createScaledBitmap(yourBitmap,(int)(yourBitmap.getWidth()*0.8), (int)(yourBitmap.getHeight()*0.8), true);
Es gibt einen großartigen Artikel zu diesem Problem auf der Android-Entwickler-Website: Große Bitmaps effizient laden