2012-12-04 6 views
9

Ich suche auf 'developer.android.com', um meine Bitmap-Datei zu verkleinern und ich habe eine Sache gefunden, die ich nicht verstehe. also schätze ich es, dass du mir ein wenig hilfst.android - calculateInSampleSize, warum behandelt Math.round die Höhe (Höhe/reqHeight), wenn Breite> Höhe?

Hier ist ein snippet von developer.android.com

public static int calculateInSampleSize(
     BitmapFactory.Options options, int reqWidth, int reqHeight) { 
    // Raw height and width of image 
    final int height = options.outHeight; 
    final int width = options.outWidth; 
    int inSampleSize = 1; 

    if (height > reqHeight || width > reqWidth) { 
    if (width > height) { 
     inSampleSize = Math.round((float)height/(float)reqHeight); 
    } else { 
     inSampleSize = Math.round((float)width/(float)reqWidth); 
    } 
    } 
    return inSampleSize; 
} 

in if-Anweisung, wenn "if (Breite> Höhe)" warum sie berechnen "(float) Größe/(float) reqHeight"?

zum Beispiel, Breite = 600, Höhe = 800, reqWidth = 100, reqHeight = 100.

In dieser Situation wäre inSampleSize 6 und die berechneten Dimensionen sind Breite = 100, Höhe = 133. Höhe ist immer noch über reqHeight ..

also, kann mir bitte jemand erklären? Entschuldigung für komplizierte Erklärung, aber Ich hoffe, jemand gibt mir eine Idee. :)

Antwort

3

Alles, was ich sagen kann ist, dass ihre Logik falsch aussieht :(Wie auch immer, diese Methode ist ziemlich einfach, also sollte es nicht so ein Problem für Sie sein, es mit den richtigen Bedingungen zu implementieren! Ich meine, wenn Sie nehmen Ein Blick auf decodeSampledBitmapFromResource, es will nur die Bitmap verkleinern, damit sie in die gewünschten Grenzen passt, also muss das ein Fehler sein.

EDIT :: Das sieht noch schlimmer aus, da es für einige nicht funktioniert Nehmen wir an, Sie haben width = 200 und height = 600. Sie setzen Ihre maximalen Grenzen auf width = 100 und height = 500. Sie haben height> width, aber wenn Sie beide das result-Ergebnis inSampleSize anpassen möchten, muss 200 sein/100 und nicht 600/500. Also im Grunde, wenn Sie die Methode neu implementieren, würde ich es so machen:

Aber das sieht aus wie zu viele Probleme mit ihrem Code für mich zu glauben, dass ich seinen Punkt richtig verstanden habe!

+0

Thx! also scheint ihre Logik falsch zu sein ..! – user1874389

3

Nun, nach vielen Problemen mit der Skalierung-Sachen, die ich denke, ich meine eigene Antwort bekam:

Mit „Große Bitmaps Laden Effizient“ von http://developer.android.com/training/displaying-bitmaps/load-bitmap.html ich unter einige meiner Ergebnisse (Originalcode stellen):

// Calculate ratios of height and width to requested height and width 
final int heightRatio = Math.round((float) height/(float) reqHeight); 
final int widthRatio = Math.round((float) width/(float) reqWidth); 

Ich arbeite derzeit an meinem Galaxy-Tab 7.7 mit 1280 x 752 Auflösung im Querformat-Modus. Stellen Sie sich ein Bild mit folgenden Angaben vor:

1920 x 1200 .. was wird passieren?

heighRatio = 1920/1280 = 1,5 und widthRatio = 1200/752 = 1,59

Beiden Nummern erhalten gerundete zu so wird das Bild nach unten durch den 2-Faktor skaliert werden, wenn ich alles verstehen Recht. Dies führt dazu, dass das Bild 1920/2 = 960 * 600 ist, was weniger als meine erforderliche Auflösung von 1280 * 752 ist.

Ich löste dies mit etagen Runde zu ersetzen:

// Calculate ratios of height and width to requested height and width 
final int heightRatio = (int)Math.floor((float) height/(float) reqHeight); 
final int widthRatio = (int)Math.floor((float) width/(float) reqWidth); 

Dies verhindert, dass tatsächlich einige meiner Bilder zu viel bekommen verkleinert. Ich untersuche derzeit noch den Parameter inSampleSize, um zu sehen, ob die Verwendung von "Brüchen" eine Option wäre. Aktuell werden alle Bilder bis zur Größe von 1280x752 (* 2) = 2560 * 1504 nicht skaliert. Das ImageView, das ich gerade schreibe, ist eine Detailansicht des Bildes, daher sollte es momentan kein großes Problem darstellen.

verwende ich die modifizierte Version der in Code in Verbindung mit:

returnview.setAdjustViewBounds(true); 

Dies wird Bilder verhindern größer als mein Bildschirm eine verkorkste Begrenzungsbox zu bekommen. Sie können es sehen, wenn Sie ein Farb-Backround auf das eigentliche Bild setzen. Außerdem kann ich mit dem jetzt fixierten Code einige onClick Handler implementieren, um zu erkennen, ob der Benutzer außerhalb meines Bildes klickt, um das Bild zu schließen.

0

Ich finde ihre Logik

if (height > reqHeight || width > reqWidth) { 
    if (width > height) { 
     inSampleSize = Math.round((float)height/(float)reqHeight); 
    } else { 
     inSampleSize = Math.round((float)width/(float)reqWidth); 
    } 
} 

zu verwirrend. Ich würde einen einfacheren Ansatz wählen. Meine Logik skaliert das Bild auf der Breite, wenn es ein horizontales Bild ist und ignoriert die erforderliche Höhe, skaliert das Bild auf Höhe, wenn es ein vertikales Bild ist, und ignoriert die erforderliche Breite.

if (height > reqHeight || width > reqWidth) { 
     if (width > height) { 
      inSampleSize = Math.round((float) width/(float) reqWidth); 
     } else { 
      inSampleSize = Math.round((float) height/(float) reqHeight); 
     } 
    } 
2

Code in obiger Frage ist ernsthaft veraltet. Wie in BitmapFactory.Options reference dokumentiert (seit 8. März 2013) inSampleSize zur nächsten Strom abgerundet von 2.

Wenn auf einen Wert> 1 gesetzt werden wird, fordert den Decoder die ursprüngliche Bild unterabzutasten, eine kleinere Rückkehr Bild um Speicher zu sparen. Die Stichprobengröße ist die Anzahl der Pixel in jeder Dimension, die einem einzelnen Pixel in der decodierten Bitmap entsprechen. Beispiel: inSampleSize == 4 gibt ein Bild zurück, das 1/4 der Breite/Höhe des Originals und 1/16 der Pixelanzahl entspricht. Jeder Wert < = 1 das gleiche wie 1. Hinweis behandelt wird: die Decoder verwendet einen Endwert basierend auf Potenzen von 2, jeder andere Wert wird auf die nächste Leistung von 2.

BitmapFactory.Options reference gerundet werden von 8. März 2013

So richtigen Code berechnen inSampleSizeLoading Large Bitmaps

public static int calculateInSampleSize(BitmapFactory.Options options, 
    int reqWidth, int reqHeight) { 

    // Raw height and width of image 
    final int height = options.outHeight; 
    final int width = options.outWidth; 
    int inSampleSize = 1; 

    if (height > reqHeight || width > reqWidth) { 

     final int halfHeight = height/2; 
     final int halfWidth = width/2; 

     // Calculate the largest inSampleSize value that is a power of 2 and keeps both 
     // height and width larger than the requested height and width. 
     while ((halfHeight/inSampleSize) > reqHeight 
       && (halfWidth/inSampleSize) > reqWidth) { 
      inSampleSize *= 2; 
     } 
    }  
    return inSampleSize; 
} 

jedoch obige Code kann zusätzlich optimiert werden würde. seit halfWidth und halfHeight sind bereits durch 2 geteilt, while loop kann neu geschrieben werden, um das Bild größer oder gleich zu den angeforderten Größenbegrenzungen zurückzugeben.

 while ((halfHeight/inSampleSize) >= reqHeight 
       && (halfWidth/inSampleSize) >= reqWidth) { 
      inSampleSize *= 2; 
     } 

Originalcode für Bild Größe 800x800 pix, die in 100x100 pix passen muss wird inSampleSize von 4 zurückkehren -> zurück Bild 200x200 pix sein wird, und modifizierte Code inSampleSize von 8 zurück -> zurück Bild 100x100 sein pix.

Anmerkung: primäre Funktion des Downsampling-Bildes mit inSampleSize und BitmapFactory.decodeXXX Methoden ist, Speicher zu bewahren, während Bilder laden, die wesentlich größer sind als die für die Anzeige benötigt werden. Diese Methoden in Kombination mit dem obigen Code ergeben immer das kleinste Bild (skaliert um die Potenz von 2), das größer (oder gleich) ist wie die angeforderten Grenzen, nicht das Bild, das in diese Grenzen passt.

0

Ihre Logik ist nicht nur hamfisted es ist eigentlich falsch. Die Sache, die Sie in dem Bild brauchen, ist es nicht zu verkleinern, bis ein Parameter kleiner als der erforderliche Wert wäre, wenn es in zwei Hälften geteilt würde, sondern stellen Sie sicher, dass keine Dimension größer als 2048 ist. Darüber können Sie oft " t rendern Sie die Textur oder zeigen Sie das Bild an. Und wenn Sie ein Bild hatten, das ungefähr 4000x1300 war und Sie sagten, dass Sie mindestens 768 wollten. Es kann die 1300 tatsächlich nicht halbieren, ohne unter diesen Wert zu fallen. Also tut es nichts und geht. Versucht, ein 4000-Wide-Bild zu laden, das nicht funktioniert.

public static int calculateInSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) { 
    int height = options.outHeight; 
    int width = options.outWidth; 
    int inSampleSize = 1; 
    while (height > maxHeight || width > maxWidth) { 
     height /= 2; 
     width /= 2; 
     inSampleSize *= 2; 
    } 
    return inSampleSize; 
} 
Verwandte Themen