Esta resposta é resumida em Carregando bitmaps grandes com eficiência
que explica como usar inSampleSize para carregar uma versão de bitmap em escala reduzida.
Em particular , os bitmaps de pré-dimensionamento explicam os detalhes de vários métodos, como combiná-los e quais são os mais eficientes em termos de memória.
Existem três maneiras dominantes de redimensionar um bitmap no Android, que têm diferentes propriedades de memória:
API createScaledBitmap
Esta API pegará um bitmap existente e criará um NOVO bitmap com as dimensões exatas que você selecionou.
No lado positivo, você pode obter exatamente o tamanho de imagem que está procurando (independentemente de sua aparência). Mas a desvantagem é que essa API requer um bitmap existente para funcionar . Significa que a imagem teria que ser carregada, decodificada e um bitmap criado, antes de ser capaz de criar uma nova versão menor. Isso é ideal em termos de obter suas dimensões exatas, mas horrível em termos de sobrecarga de memória adicional. Como tal, isso é uma espécie de quebra de negócio para a maioria dos desenvolvedores de aplicativos que tendem a se preocupar com a memória
Sinalizador inSampleSize
BitmapFactory.Options
tem uma propriedade inSampleSize
que irá redimensionar sua imagem enquanto a decodifica, para evitar a necessidade de decodificar para um bitmap temporário. Este valor inteiro usado aqui carregará uma imagem em tamanho 1 / x reduzido. Por exemplo, definir inSampleSize
como 2 retorna uma imagem com metade do tamanho, e definir como 4 retorna uma imagem com 1/4 do tamanho. Basicamente, os tamanhos das imagens serão sempre um pouco menores do que o tamanho da fonte.
Do ponto de vista da memória, usar inSampleSize
é uma operação muito rápida. Efetivamente, ele só decodificará cada X pixel de sua imagem em seu bitmap resultante. Existem dois problemas principais inSampleSize
:
Não fornece resoluções exatas . Ele apenas diminui o tamanho do seu bitmap em uma potência de 2.
Não produz o redimensionamento de melhor qualidade . A maioria dos filtros de redimensionamento produz imagens com boa aparência ao ler blocos de pixels e, em seguida, ponderá-los para produzir o pixel redimensionado em questão. inSampleSize
evita tudo isso lendo apenas alguns pixels. O resultado é bastante eficiente e com pouca memória, mas a qualidade é prejudicada.
Se você está lidando apenas com o encolhimento de sua imagem em algum tamanho pow2, e a filtragem não é um problema, então você não encontrará um método mais eficiente em memória (ou desempenho) do que inSampleSize
.
Sinalizadores inScaled, inDensity, inTargetDensity
Se você precisa redimensionar uma imagem para uma dimensão que não é igual a uma potência de dois, então você vai precisar do inScaled
, inDensity
e inTargetDensity
bandeiras de BitmapOptions
. Quando o inScaled
sinalizador for definido, o sistema derivará o valor de escala a ser aplicado ao seu bitmap, dividindo o inTargetDensity
pelos inDensity
valores.
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
Usar este método redimensionará sua imagem e também aplicará um 'filtro de redimensionamento' a ela, ou seja, o resultado final parecerá melhor porque alguma matemática adicional foi levada em consideração durante a etapa de redimensionamento. Mas esteja avisado: essa etapa de filtro extra, leva mais tempo de processamento e pode aumentar rapidamente para imagens grandes, resultando em redimensionamentos lentos e alocações de memória extra para o próprio filtro.
Geralmente não é uma boa ideia aplicar essa técnica a uma imagem significativamente maior do que o tamanho desejado, devido à sobrecarga de filtragem extra.
Combinação mágica
De uma perspectiva de memória e desempenho, você pode combinar essas opções para obter os melhores resultados. (definindo o inSampleSize
, inScaled
, inDensity
e inTargetDensity
bandeiras)
inSampleSize
será aplicado primeiro à imagem, colocando-a na próxima potência de dois MAIOR do que o tamanho de destino. Em seguida, inDensity
& inTargetDensity
são usados para dimensionar o resultado para as dimensões exatas que você deseja, aplicando uma operação de filtro para limpar a imagem.
Combinar esses dois é uma operação muito mais rápida, uma vez que a inSampleSize
etapa reduzirá o número de pixels que a etapa baseada em densidade resultante precisará para aplicar seu filtro de redimensionamento.
mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
Se você precisar ajustar uma imagem a dimensões específicas, e alguma filtragem mais agradável, essa técnica é a melhor ponte para obter o tamanho certo, mas feita em uma operação rápida e com pouca memória.
Obtendo as dimensões da imagem
Obtendo o tamanho da imagem sem decodificar a imagem inteira Para redimensionar seu bitmap, você precisará saber as dimensões de entrada. Você pode usar o inJustDecodeBounds
sinalizador para ajudá-lo a obter as dimensões da imagem, sem a necessidade de realmente decodificar os dados de pixel.
// Decode just the boundaries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;
//now go resize the image to the size you want
Você pode usar este sinalizador para decodificar o tamanho primeiro e, em seguida, calcular os valores adequados para dimensionar a sua resolução alvo.