2010-04-05 2 views
59

У меня есть изображение большого размера. Во время выполнения я хочу прочитать изображение из хранилища и масштабировать его, чтобы уменьшить его вес и размер, и я могу использовать его как миниатюру. Когда пользователь нажимает на миниатюру, я хочу отобразить полноразмерное изображение.Android, как создать временную эскиз

ответ

42

мое решение

byte[] imageData = null; 

     try  
     { 

      final int THUMBNAIL_SIZE = 64; 

      FileInputStream fis = new FileInputStream(fileName); 
      Bitmap imageBitmap = BitmapFactory.decodeStream(fis); 

      imageBitmap = Bitmap.createScaledBitmap(imageBitmap, THUMBNAIL_SIZE, THUMBNAIL_SIZE, false); 

      ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
      imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); 
      imageData = baos.toByteArray(); 

     } 
     catch(Exception ex) { 

     } 
+1

Мои файлы были большими, поэтому мне пришлось использовать sub-выборку в шаге 'BitmapFactory.decodeStream (fis);'. См. [Docs] (http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize) для более подробной информации о подэмплинге. – Diederik

+4

Лучше использовать класс 'ThumbnailUils' для Android, как показано ниже. – afollestad

+1

@afollestad Не совсем, этот подход правильный. Использование ThumbnailUtils - это только хорошая идея, если вы на 100% уверены, что работаете с небольшими файлами. – GuillermoMP

6

Используйте BitmapFactory.decodeFile(...), чтобы получить объект Bitmap и установите его на ImageView с ImageView.setImageBitmap().

На ImageView установить размеры макета на что-то маленькое, например:

android:layout_width="66dip" android:layout_height="48dip" 

Добавить onClickListener в ImageView и начать новый вид деятельности, в котором отображать изображение в полном размере с

android:layout_width="wrap_content" android:layout_height="wrap_content" 

или укажите какой-либо более крупный размер.

+11

Если у вас есть несколько изображений, вы должны заранее рассмотреть его масштабирование до размера большого пальца. в противном случае это может замедлить производительность при перемещении набора. – Moritz

+5

Действительно, и для этого вы должны использовать Bitmap.createScaledBitmap (originalBitmap, newWidth, newHeight, false); –

+1

dones следующий метод также уменьшает вес изображения? Bitmap.createScaledBitmap (originalBitmap, newWidth, newHeight, false) –

9

Вот более полное решение для масштабирования растрового изображения до размера миниатюр. Он расширяется в решении Bitmap.createScaledBitmap, поддерживая пропорции изображений, а также дополняя их одинаковой шириной, чтобы они выглядели хорошо в ListView.

Кроме того, было бы лучше всего сделать это масштабирование один раз и сохранить полученный битмап как blob в вашей базе данных Sqlite. Я включил фрагмент кода о том, как преобразовать Bitmap в массив байтов для этой цели.

public static final int THUMBNAIL_HEIGHT = 48; 
public static final int THUMBNAIL_WIDTH = 66; 

imageBitmap = BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length); 
Float width = new Float(imageBitmap.getWidth()); 
Float height = new Float(imageBitmap.getHeight()); 
Float ratio = width/height; 
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, (int)(THUMBNAIL_HEIGHT*ratio), THUMBNAIL_HEIGHT, false); 

int padding = (THUMBNAIL_WIDTH - imageBitmap.getWidth())/2; 
imageView.setPadding(padding, 0, padding, 0); 
imageView.setImageBitmap(imageBitmap); 



ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); 
byte[] byteArray = baos.toByteArray(); 
+0

Есть ли причина, по которой вы изменили порядок аргументов для 'THUMBNAIL_HEIGHT' и' THUMBNAIL_HEIGHT' для 'createScaledBitmap'? – jayeffkay

123

Попробуйте

Bitmap ThumbImage = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(imagePath), THUMBSIZE, THUMBSIZE); 

Эта утилита доступна из API_LEVEl 8. [Source]

+1

Используя этот код, вы фактически загружаете в память копию большого растрового изображения, поэтому это не очень хороший способ управления большими изображениями. – GuillermoMP

+0

@GuillermoMP Каков же тогда хороший способ? – Rafouille

+5

Правильный способ - декодировать уменьшенную версию файла. Другие ответы предлагают такой подход. Также официальные документы хорошо объясняют процесс: https://developer.android.com/intl/es/training/displaying-bitmaps/load-bitmap.html. Поскольку этот вопрос является наиболее проголосовавшим (из-за его простоты), я просто хотел предупредить всех, что это не лучший способ. – GuillermoMP

3
/** 
* Creates a centered bitmap of the desired size. 
* 
* @param source original bitmap source 
* @param width targeted width 
* @param height targeted height 
* @param options options used during thumbnail extraction 
*/ 
public static Bitmap extractThumbnail(
     Bitmap source, int width, int height, int options) { 
    if (source == null) { 
     return null; 
    } 

    float scale; 
    if (source.getWidth() < source.getHeight()) { 
     scale = width/(float) source.getWidth(); 
    } else { 
     scale = height/(float) source.getHeight(); 
    } 
    Matrix matrix = new Matrix(); 
    matrix.setScale(scale, scale); 
    Bitmap thumbnail = transform(matrix, source, width, height, 
      OPTIONS_SCALE_UP | options); 
    return thumbnail; 
} 
+0

где is transform (matrix, source, width, height, OPTIONS_SCALE_UP | options) Метод – Andy

+0

https://code.google.com/p/kontalk/source/browse/src/org/kontalk/xmpp/util/ThumbnailUtils. java? repo = androidclient & name = xmpp & r = f879e85d21d6e0a8a6f736ebe90c03e851b51436 – user1546570

+0

Thanx дорого получил его. – Andy

10

Лучшее решение я нашел следующее. По сравнению с другими решениями, для этого нет необходимости загружать полное изображение для создания миниатюры, поэтому оно более эффективно! Его предел в том, что вы не можете иметь эскиз с точной шириной и высотой, но решение как можно ближе.

File file = ...; // the image file 
Options bitmapOptions = new Options(); 

bitmapOptions.inJustDecodeBounds = true; // obtain the size of the image, without loading it in memory 
BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOptions); 

// find the best scaling factor for the desired dimensions 
int desiredWidth = 400; 
int desiredHeight = 300; 
float widthScale = (float)bitmapOptions.outWidth/desiredWidth; 
float heightScale = (float)bitmapOptions.outHeight/desiredHeight; 
float scale = Math.min(widthScale, heightScale); 

int sampleSize = 1; 
while (sampleSize < scale) { 
    sampleSize *= 2; 
} 
bitmapOptions.inSampleSize = sampleSize; // this value must be a power of 2, 
             // this is why you can not have an image scaled as you would like 
bitmapOptions.inJustDecodeBounds = false; // now we want to load the image 

// Let's load just the part of the image necessary for creating the thumbnail, not the whole image 
Bitmap thumbnail = BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOptions); 

// Save the thumbnail 
File thumbnailFile = ...; 
FileOutputStream fos = new FileOutputStream(thumbnailFile); 
thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, fos); 
fos.flush(); 
fos.close(); 

// Use the thumbail on an ImageView or recycle it! 
thumbnail.recycle(); 
+2

Это лучше всего подходит для устройств с низкой памятью – Lunatikul

+0

Спасибо. Он решил проблему с исключением из памяти. –

0

Если вы хотите получить высококачественный результат, используйте библиотеку [RapidDecoder] [1]. Это просто следующим образом:

import rapid.decoder.BitmapDecoder; 
... 
Bitmap bitmap = BitmapDecoder.from(getResources(), R.drawable.image) 
          .scale(width, height) 
          .useBuiltInDecoder(true) 
          .decode(); 

Не забывайте использовать встроенный декодер, если вы хотите масштабировать до менее чем 50% и результат HQ.

0

Я нашел легкий способ сделать это

Bitmap thumbnail = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(mPath),200,200) 

Синтаксис

Bitmap thumbnail = ThumbnailUtils.extractThumbnail(Bitmap source,int width,int height) 

ИЛИ

использовать Пикассо зависимостях

компиляции 'com.squareup.picasso: Picasso: 2.5.2'

Picasso.with(context) 
    .load("file:///android_asset/DvpvklR.png") 
    .resize(50, 50) 
    .into(imageView2); 

Ссылка Picasso

0

Этот ответ основан на решении, представленном в https://developer.android.com/topic/performance/graphics/load-bitmap.html (без использования внешних библиотек) с некоторыми изменения меня, чтобы сделать его функциональность лучше и практичнее.

Некоторые замечания по поводу этого решения:

  1. Предполагается, что вы хотите сохранить пропорции. Другими слова:

    finalWidth/finalHeight == sourceBitmap.getWidth()/sourceBitmap.getWidth() (Вне зависимости от литья и округления вопросов)

  2. Предполагается, что у вас есть два значения (maxWidth & maxHeight), что вы хотите любого из размеров ваше окончательное растровое изображение не превышает его соответствующее значение. Другими словами:

    finalWidth <= maxWidth && finalHeight <= maxHeight

    Так minRatio был помещен в качестве основы расчетов (см реализацию). UNLIKE основное решение, которое положило maxRatio в качестве основы расчетов в фактических. Кроме того, расчет inSampleSize был намного лучше (более логичный, краткий и эффективный).

  3. Предполагается, что вы хотите (по крайней мере) один из конечных размеров имеет точно значение своего соответствующего MaxValue (каждый из них можно было, с учетом вышеуказанных допущений). Другими словами:

    finalWidth == maxWidth || finalHeight == maxHeight

    Конечный дополнительный шаг в сравнении с основным раствором (Bitmap.createScaledBitmap(...)) для этого ограничения «именно».Очень важно отметить , вы не должны делать этот шаг сначала (например, the accepted answer), из-за его значительного потребления памяти в случае огромных изображений!

  4. Он предназначен для декодирования file. Вы можете изменить его, как базовое решение для декодирования resource (или все, что поддерживает BitmapFactory).

Реализация:

public static Bitmap decodeSampledBitmap(String pathName, int maxWidth, int maxHeight) { 
    // First decode with inJustDecodeBounds=true to check dimensions 
    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeFile(pathName, options); 

    final float wRatio_inv = (float) options.outWidth/maxWidth, 
      hRatio_inv = (float) options.outHeight/maxHeight; // Working with inverse ratios is more comfortable 
    final int finalW, finalH, minRatio_inv /* = max{Ratio_inv} */; 

    if (wRatio_inv > hRatio_inv) { 
     minRatio_inv = (int) wRatio_inv; 
     finalW = maxWidth; 
     finalH = Math.round(options.outHeight/wRatio_inv); 
    } else { 
     minRatio_inv = (int) hRatio_inv; 
     finalH = maxHeight; 
     finalW = Math.round(options.outWidth/hRatio_inv); 
    } 

    options.inSampleSize = pow2Ceil(minRatio_inv); // pow2Ceil: A utility function that comes later 
    options.inJustDecodeBounds = false; // Decode bitmap with inSampleSize set 

    return Bitmap.createScaledBitmap(BitmapFactory.decodeFile(pathName, options), 
      finalW, finalH, true); 
} 

/** 
* @return the largest power of 2 that is smaller than or equal to number. 
* WARNING: return {0b1000000...000} for ZERO input. 
*/ 
public static int pow2Ceil(int number) { 
    return 1 << -(Integer.numberOfLeadingZeros(number) + 1); // is equivalent to: 
    // return Integer.rotateRight(1, Integer.numberOfLeadingZeros(number) + 1); 
} 

Пример использования, в случае, если вы имеете imageView с определенным значением для layout_width (match_parent или явного значения) и неопределенные значение для layout_height (wrap_content) и вместо этого определено значение для maxHeight:

imageView.setImageBitmap(decodeSampledBitmap(filePath, 
     imageView.getWidth(), imageView.getMaxHeight())); 
Смежные вопросы