Изменение размера большого растрового файла для масштабирования выходного файла на Android

У меня есть большой битмап (скажем, 3888x2592) в файле. Теперь я хочу изменить размер растрового изображения до 800x533 и сохранить его в другом файле. Я обычно масштабировал растровое изображение, вызывая метод Bitmap.createBitmap, но для первого аргумента он должен иметь исходный битмап, который я не могу предоставить, поскольку загрузка исходного изображения в объект Bitmap будет, конечно, превышать память (см. здесь, например).

Я также не могу прочитать растровое изображение с, например, BitmapFactory.decodeFile(file, options), предоставляя BitmapFactory.Options.inSampleSize, потому что я хочу изменить его размер до точной ширины и высоты. Использование inSampleSize приведет к изменению размера растрового изображения до 972x648 (если я использую inSampleSize=4) или 778x518 (если я использую inSampleSize=5, который даже не имеет значения 2).

Я также хотел бы избежать чтения изображения с использованием inSampleSize с, например, 972x648 на первом шаге, а затем изменить его размер до 800x533 на втором шаге, потому что качество будет плохим по сравнению с прямым изменением размера оригинала изображение.

Подводя итог моему вопросу: Есть ли способ прочитать большой файл изображения с 10 или более мегабайтами и сохранить его в новом файле изображения, измененном до определенной ширины и высоты, без получения исключения OutOfMemory?

Я также пробовал BitmapFactory.decodeFile(file, options) и устанавливал значения Options.outHeight и Options.outWidth вручную до 800 и 533, но это не работает.

+201
26 июл. '10 в 0:06
источник поделиться
21 ответ

Нет.. Мне бы очень хотелось, чтобы кто-то меня исправил, но я принял подход load/resize, который вы пробовали в качестве компромисса.

Вот шаги для просмотра:

  • Рассчитайте максимально возможный inSampleSize, который все еще дает изображение, большее, чем ваша цель.
  • Загрузите изображение с помощью BitmapFactory.decodeFile(file, options), передав в качестве параметра параметрSampleSize.
  • Измените размер до требуемых размеров с помощью Bitmap.createScaledBitmap().
+140
26 июл. '10 в 0:56
источник

Связанные вопросы


Похожие вопросы

Джастин отвечает на перевод кода (отлично работает для меня):

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;
}
+89
13 дек. '11 в 23:26
источник

Это "Mojo Risin" и "Ofir solutions" вместе ". Это даст вам пропорционально измененное изображение с границами максимальной ширины и максимальной высоты.

  • Он только считывает метаданные, чтобы получить исходный размер (options.inJustDecodeBounds)
  • Он использует грубое изменение размера для сохранения памяти (itmap.createScaledBitmap)
  • Он использует точно измененное изображение на основе грубого бита, созданного ранее.

Для меня он отлично работает на 5 MegaPixel изображениях ниже.

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);
}
+41
10 февр. '12 в 21:15
источник

Почему бы не использовать API?

int h = 48; // height in pixels
int w = 48; // width in pixels    
Bitmap scaled = Bitmap.createScaledBitmap(largeBitmap, w, h, true);
+22
05 сент. '10 в 17:41
источник

Подтверждая еще один отличный ответ, лучший код, который я видел еще для этого, содержится в документации для инструмента для съемки фотографий.

См. раздел "Декодирование масштабированного изображения".

http://developer.android.com/training/camera/photobasics.html

Решение, которое оно предлагает, представляет собой изменение размера, а затем масштабное решение, подобное другим, но оно довольно аккуратное.

Я скопировал код ниже как готовую функцию для удобства.

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);
}
+19
15 окт. '13 в 22:06
источник

Прочитав эти ответы и документацию по Android, введите код для изменения размера растрового изображения без его загрузки в память:

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);
}
+18
22 июн. '14 в 20:47
источник

Это может быть полезно для кого-то другого, рассматривающего этот вопрос. Я переписал код Justin, чтобы позволить методу получать требуемый объект размера цели. Это очень хорошо работает при использовании Canvas. Весь кредит должен пойти в JUSTIN за его отличный исходный код.

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

Код Justin очень эффективен для сокращения накладных расходов при работе с большими растровыми изображениями.

+5
18 февр. '13 в 13:03
источник

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

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);
+5
26 июл. '10 в 12:45
источник

Я не знаю, подходит ли мое решение, но я достиг загрузки растрового изображения с желаемым масштабированием с помощью опций inDensity и inTargetDensity. inDensity является 0 изначально, когда не загружается ресурс, пригодный для переноски, поэтому этот подход предназначен для загрузки изображений без ресурсов.

Переменные imageUri, maxImageSideLength и context являются параметрами моего метода. Для ясности я опубликовал только реализацию метода без обертывания AsyncTask.

            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;
+4
07 окт. '14 в 15:00
источник

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

  • Узнайте размер измененного изображения с вызовом BitmapFactory.decodeFile и предоставив checkSizeOptions.inJustDecodeBounds
  • Рассчитайте максимальный максимум, который можно использовать в файлеSampleSize, который вы можете использовать на своем устройстве, чтобы не превышать память. bitmapSizeInBytes = 2 * width * height; Как правило, для вашей картинки вSampleSize = 2 будет хорошо, так как вам понадобится только 2 * 1944x1296) = 4.8Mbб, которые должны быть в памяти
  • Использовать BitmapFactory.decodeFile с inSampleSize для загрузки растрового изображения
  • Масштабируйте растровое изображение в точном размере.

Мотивация: масштабирование с несколькими шагами может дать вам изображение более высокого качества, однако нет гарантии, что он будет работать лучше, чем использование high inSampleSize. На самом деле, я думаю, что вы также можете использовать inSampleSize, например 5 (не pow of 2), чтобы иметь прямое масштабирование за одну операцию. Или просто используйте 4, а затем вы можете просто использовать это изображение в пользовательском интерфейсе. если вы отправляете его на сервер, - вы можете сделать масштабирование до точного размера на стороне сервера, что позволит вам использовать расширенные методы масштабирования.

Примечания: если битмап, загруженный на этапе 3, по крайней мере в 4 раза больше (так что ширина 4 * targetWidth < width), вы, вероятно, можете использовать несколько размеров для достижения лучшего качества. по крайней мере, что работает в общей java, в android у вас нет возможности указать интерполяцию, используемую для масштабирования http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html

+2
23 сент. '10 в 7:45
источник

Выше код сделал немного чище. InputStreams, наконец, закрывают упаковку, чтобы они также закрылись:

* Примечание Вход: InputStream is, int w, int h
Выход: Растровое изображение

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

    }
+2
11 апр. '12 в 22:25
источник

Я использовал такой код:

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

Я попробовал оригинальное изображение 1230 x 1230, и получил битмап говорит 330 x 330.
И если вы попробовали 2590 x 3849, я получаю OutOfMemoryError.

Я проследил его, он все равно бросает OutOfMemoryError в строку "BitmapFactory.decodeStream(is, null, options);", если оригинальное растровое изображение слишком велико...

+2
30 нояб. '11 в 18:37
источник

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

http://bricolsoftconsulting.com/2012/12/07/handling-large-images-on-android/

+1
08 дек. '12 в 21:49
источник

Если вы абсолютно хотите сделать одно изменение размера, вы, вероятно, можете загрузить всю растровую карту, если android: largeHeap = true, но, как вы видите, это действительно не рекомендуется.

Из документов: андроид: largeHeap Должны ли быть созданы ваши прикладные процессы с большой кучей Dalvik. Это относится ко всем процессам, созданным для приложения. Он применяется только к первому приложению, загружаемому в процесс; если вы используете общий идентификатор пользователя, чтобы разрешить нескольким приложениям использовать процесс, все они должны использовать эту опцию последовательно или у них будут непредсказуемые результаты. Большинство приложений не должны этого нуждаться и вместо этого должны сосредоточиться на сокращении общего использования памяти для повышения производительности. Включение этого также не гарантирует фиксированного увеличения доступной памяти, поскольку некоторые устройства ограничены их общей доступной памятью.

+1
23 мая '13 в 10:46
источник

Чтобы масштабировать изображение "правильным" способом, не пропуская ни одного пикселя, вам нужно будет подключиться к декодеру изображения, чтобы выполнить последовательную выборку по строке. Android (и библиотека Skia, которая лежит в основе этого) не предоставляет таких крючков, поэтому вам придется сворачивать самостоятельно. Предполагая, что вы говорите jpeg-изображениями, лучше всего использовать libjpeg напрямую, в C.

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

+1
04 авг. '12 в 3:01
источник

Я использую Integer.numberOfLeadingZeros чтобы вычислить лучший размер выборки, лучшую производительность.

Полный код в котлине:

@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)
}
0
29 янв. '19 в 5:37
источник

Это сработало для меня. Функция получает путь к файлу на SD-карте и возвращает битмап в максимальном отображаемом размере. Код из Ofir с некоторыми изменениями, такими как файл изображения на sd, вместо Ressource, а witdth и heigth - из Display Object.

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

}
0
12 февр. '14 в 17:33
источник

Об этой конкретной проблеме на веб-сайте разработчика Android есть отличная статья: Эффективная загрузка больших растровых изображений

0
07 янв. '13 в 11:55
источник
 Bitmap yourBitmap;
 Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true);

или

 resized = Bitmap.createScaledBitmap(yourBitmap,(int)(yourBitmap.getWidth()*0.8), (int)(yourBitmap.getHeight()*0.8), true);
0
06 авг. '14 в 9:56
источник

Вот код, который я использую, который не имеет проблем с декодированием больших изображений в памяти на Android. Я смог декодировать изображения размером более 20 МБ, пока мои входные параметры составляют около 1024х1024. Вы можете сохранить возвращенное растровое изображение в другой файл. Ниже этот метод - еще один метод, который я также использую для масштабирования изображений в новом растровом изображении. Не стесняйтесь использовать этот код, как хотите.

/*****************************************************************************
 * 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

ПРИМЕЧАНИЕ. Методы не имеют ничего общего друг с другом, кроме описанного выше метода декодирования createScaledBitmap. Ширина и высота записи могут меняться от исходного изображения.

/*****************************************************************************
 * 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
-1
08 июл. '14 в 16:33
источник

Измените размер растрового изображения, используя следующий код

    public static Bitmap decodeFile(File file, int reqWidth, int reqHeight){

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;        
    BitmapFactory.decodeFile(file.getPath(), options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(file.getPath(), options);
   }

    private 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) {

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

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
     }

     return inSampleSize;
   }    

То же самое объясняется в следующем совете/трюке

http://www.codeproject.com/Tips/625810/Android-Image-Operations-Using-BitmapFactory

-2
29 июл. '13 в 11:19
источник

Посмотрите другие вопросы по меткам или Задайте вопрос