2013-12-15 3 views
6

Я работаю над Android-приложением, которое имеет функцию захвата камеры и загрузки фотографий. Если устройство имеет камеру с высоким разрешением, размер захваченного изображения будет действительно большим (1 ~ 3 МБ или более).
Поскольку приложение должно загрузить это изображение на сервер, мне нужно будет сжать изображение перед загрузкой. Например, если камера захватила фотографию с полным разрешением 1920x1080, идеальным выходом будет сохранение соотношения изображения 16: 9, сжатие изображения 640x360 для уменьшения некоторого качества изображения и уменьшение его размера в байтах.Android - масштабирование и сжатие растрового изображения

Вот мой код (ссылка от Google):

/** 
* this class provide methods that can help compress the image size. 
* 
*/ 
public class ImageCompressHelper { 

/** 
* Calcuate how much to compress the image 
* @param options 
* @param reqWidth 
* @param reqHeight 
* @return 
*/ 
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; 
} 

/** 
* resize image to 480x800 
* @param filePath 
* @return 
*/ 
public static Bitmap getSmallBitmap(String filePath) { 

    File file = new File(filePath); 
    long originalSize = file.length(); 

    MyLogger.Verbose("Original image size is: " + originalSize + " bytes."); 

    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeFile(filePath, options); 

    // Calculate inSampleSize based on a preset ratio 
    options.inSampleSize = calculateInSampleSize(options, 480, 800); 

    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 

    Bitmap compressedImage = BitmapFactory.decodeFile(filePath, options); 

    MyLogger.Verbose("Compressed image size is " + sizeOf(compressedImage) + " bytes"); 

    return compressedImage; 
} 

Проблема с выше код:

  1. Он не может держать соотношение, код заставляет изображение, чтобы изменить на 480x800. если пользователь захватил изображение в другом соотношении, изображение не будет выглядеть хорошо после сжатия.
  2. Не работает нормально. Код всегда будет изменять размер изображения до 7990272 байт независимо от исходного размера файла. Если первоначальный размер изображения довольно мал уже, он будет делать это большой (мой результат теста, чтобы сделать снимок моей стены, которая в значительной степени моно-цвета):

    Original image size is: 990092 bytes.
    Compressed image size is 7990272 bytes

Я спрашиваю, есть ли предложение улучшить способ сжимать фотографию, чтобы ее можно было загружать плавно?

+2

Вместо того чтобы использовать жестко запрограммированный размер 480х800 - вы должны рассчитать динамический размер выходного Bitmap, который поддерживает нужное соотношение сторон я.e для пейзажных и портретных изменений. И для размера изображения - имейте в виду, что вы сравниваете исходный * сжатый размер файла с масштабированным * несжатым * Размер растрового изображения. – harism

ответ

12
  1. Вам необходимо определить лимит ширины или высоты (не оба, очевидно). Затем замените эти фиксированные размеры изображения с расчетными, говорят:

    int targetWidth = 640; // your arbitrary fixed limit 
    int targetHeight = (int) (originalHeight * targetWidth/(double) originalWidth); // casts to avoid truncating 
    

    (Добавить проверки и расчета вариантов для ландшафта/портретной ориентации, по мере необходимости.)

  2. Как @harism также комментировал: большой размер вы упомянутый размер необработанный размер этого 480x800 растрового изображения, а не размер файла, который должен быть JPEG в вашем случае. Как вы собираетесь сохранить это растровое изображение, BTW? В вашем коде нет сохраненной части.

    См this question here для помощи в этом случае, с ключом нечто вроде:

    OutputStream imagefile = new FileOutputStream("/your/file/name.jpg"); 
    // Write 'bitmap' to file using JPEG and 80% quality hint for JPEG: 
    bitmap.compress(CompressFormat.JPEG, 80, imagefile); 
    
2

Во-первых я проверить размер изображения, то я сжать изображение в зависимости от размера и получить сжатый растровое изображение затем отправить этот точечный рисунок к серверу для сжатого вызова растрового ниже Funtion мы должны пройти путь к изображению в поле ниже Funtion

public Bitmap get_Picture_bitmap(String imagePath) { 

    long size_file = getFileSize(new File(imagePath)); 

    size_file = (size_file)/1000;// in Kb now 
    int ample_size = 1; 

    if (size_file <= 250) { 

     System.out.println("SSSSS1111= " + size_file); 
     ample_size = 2; 

    } else if (size_file > 251 && size_file < 1500) { 

     System.out.println("SSSSS2222= " + size_file); 
     ample_size = 4; 

    } else if (size_file >= 1500 && size_file < 3000) { 

     System.out.println("SSSSS3333= " + size_file); 
     ample_size = 8; 

    } else if (size_file >= 3000 && size_file <= 4500) { 

     System.out.println("SSSSS4444= " + size_file); 
     ample_size = 12; 

    } else if (size_file >= 4500) { 

     System.out.println("SSSSS4444= " + size_file); 
     ample_size = 16; 
    } 

    Bitmap bitmap = null; 

    BitmapFactory.Options bitoption = new BitmapFactory.Options(); 
    bitoption.inSampleSize = ample_size; 

    Bitmap bitmapPhoto = BitmapFactory.decodeFile(imagePath, bitoption); 

    ExifInterface exif = null; 
    try { 
     exif = new ExifInterface(imagePath); 
    } catch (IOException e) { 
     // Auto-generated catch block 
     e.printStackTrace(); 
    } 
    int orientation = exif 
      .getAttributeInt(ExifInterface.TAG_ORIENTATION, 1); 
    Matrix matrix = new Matrix(); 

    if ((orientation == 3)) { 
     matrix.postRotate(180); 
     bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0, 
       bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix, 
       true); 

    } else if (orientation == 6) { 
     matrix.postRotate(90); 
     bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0, 
       bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix, 
       true); 

    } else if (orientation == 8) { 
     matrix.postRotate(270); 
     bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0, 
       bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix, 
       true); 

    } else { 
     matrix.postRotate(0); 
     bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0, 
       bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix, 
       true); 

    } 

    return bitmap; 

} 

GetFileSize Funtion для получения размера изображений

public long getFileSize(final File file) { 
    if (file == null || !file.exists()) 
     return 0; 
    if (!file.isDirectory()) 
     return file.length(); 
    final List<File> dirs = new LinkedList<File>(); 
    dirs.add(file); 
    long result = 0; 
    while (!dirs.isEmpty()) { 
     final File dir = dirs.remove(0); 
     if (!dir.exists()) 
      continue; 
     final File[] listFiles = dir.listFiles(); 
     if (listFiles == null || listFiles.length == 0) 
      continue; 
     for (final File child : listFiles) { 
      result += child.length(); 
      if (child.isDirectory()) 
       dirs.add(child); 
     } 
    } 

    return result; 
} 
Смежные вопросы