Android에서 큰 비트맵 파일 크기를 출력 파일 크기로 조정
파일에 큰 비트맵(예: 3888x2592)이 있습니다.비트맵의 크기를 800x533으로 조정하고 다른 파일에 저장합니다.보통 비트맵의 크기를 조정할 때는Bitmap.createBitmap
메서드는 첫 번째 인수로 소스 비트맵이 필요합니다. 원래 이미지를 비트맵 개체에 로드하면 당연히 메모리를 초과하기 때문에 제공할 수 없습니다(예: 여기 참조).
예를 들어 비트맵을 읽을 수도 없습니다.BitmapFactory.decodeFile(file, options)
, 제공하기BitmapFactory.Options.inSampleSize
, 정확한 폭과 높이로 크기를 조정하고 싶기 때문입니다.으로.inSampleSize
비트맵 크기를 972x648로 조정합니다(사용하는 경우).inSampleSize=4
) 또는 778x518로(사용하는 경우)inSampleSize=5
, 2)의 힘도 아닌 것을 의미합니다.
또한 첫 번째 단계에서 972x648을 사용하여 SampleSize에서 이미지를 읽고 두 번째 단계에서 정확히 800x533으로 크기를 조정하는 것을 피하고 싶습니다. 왜냐하면 원래 이미지의 직접 크기를 조정하는 것에 비해 품질이 좋지 않기 때문입니다.
제 질문을 요약하자면:OutOfMemory 예외 없이 10MP 이상의 대용량 이미지 파일을 읽고 특정 새 너비와 높이로 크기를 조정한 새 이미지 파일에 저장할 수 있는 방법이 있습니까?
저도 노력했습니다.BitmapFactory.decodeFile(file, options)
Options.outHeight and Options.outWidth 값을 수동으로 800과 533으로 설정합니다.
아니요. 누군가 저를 고쳐줬으면 좋겠는데, 당신이 시도한 부하/크기 조정 방법을 타협안으로 받아들였습니다.
검색하는 모든 사용자를 위한 단계는 다음과 같습니다.
- 가능한 최대를 계산합니다.
inSampleSize
목표치보다 더 큰 이미지를 얻을 수 있습니다. - 다음을 사용하여 이미지 로드
BitmapFactory.decodeFile(file, options)
, SampleSize를 옵션으로 전달합니다. - 원하는 치수로 크기 조정하기
Bitmap.createScaledBitmap()
.
코드로 번역된 Justin 답변(나에게 딱 맞는 답변):
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;
}
이것은 '모조 리신'과 '오피르'의 솔루션 '결합'입니다.이렇게 하면 최대 너비 및 최대 높이 경계가 있는 비례 크기의 이미지가 제공됩니다.
- 원래 크기를 얻기 위해 메타 데이터만 읽습니다(options.inJustDecodeBounds).
- 대략적인 크기를 사용하여 메모리를 저장합니다(itmap.createScaled Bitmap).
- 앞서 제작한 거친 비트앰프를 기반으로 정확한 크기의 이미지를 사용합니다.
저는 아래 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);
}
API를 사용하지 않는 이유는 무엇입니까?
int h = 48; // height in pixels
int w = 48; // width in pixels
Bitmap scaled = Bitmap.createScaledBitmap(largeBitmap, w, h, true);
지금까지 제가 본 최고의 코드는 사진 촬영 도구에 대한 설명서입니다.
"스케일링된 이미지 디코딩" 섹션을 참조하십시오.
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);
}
이 답변과 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);
}
크기가 큰 비트맵을 가지고 있고 크기가 조정된 비트맵을 디코딩하고 싶을 때 다음을 사용합니다.
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);
이 질문을 보는 다른 사용자에게 유용할 수 있습니다.저는 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;
}
}
저스틴의 코드는 큰 비트맵으로 작업하는 오버헤드를 줄이는 데 매우 효과적입니다.
제 솔루션이 최선의 방법인지는 모르겠지만, 사용자가 원하는 확장 기능을 통해 비트맵을 로드하는 데 성공했습니다.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;
정확한 크기로 사이즈를 조정하고 필요한 만큼 품질을 유지하고 싶은 점을 고려하면 시도해보셔야 할 것 같습니다.
- BitmapFactory.decodeFile을 호출하고 checkSizeOptions.inJustDecodeBounds를 제공하여 크기가 조정된 이미지의 크기를 확인합니다.
- 메모리를 초과하지 않도록 장치에서 사용할 수 있는 SampleSize에서 가능한 최대 값을 계산합니다. 비트맵SizeInBytes = 2*width*height. 일반적으로 SampleSize=2의 사진의 경우 2* 1944x1296)=4만 필요하므로 괜찮습니다.메모리에 피트가 있어야 하는 8Mb б
- SampleSize 내의 BitmapFactory.decodeFile을 사용하여 비트맵을 로드합니다.
- 비트맵의 크기를 정확한 크기로 조정합니다.
동기부여: 여러 단계의 스케일링을 통해 높은 화질의 사진을 얻을 수 있지만, 높은 샘플 크기를 사용하는 것보다 더 잘 작동할 것이라는 보장은 없습니다.실제로 SampleSize에서 (2의 pow가 아닌) 5와 같이 사용하여 한 작업에서 직접 스케일링을 할 수도 있다고 생각합니다.또는 4를 사용하면 UI에서 해당 이미지를 사용할 수 있습니다. 서버로 전송하면 고급 스케일링 기술을 사용할 수 있는 서버 측에서 정확한 크기로 스케일링할 수 있습니다.
참고: 3단계에서 로드된 비트맵이 최소 4배 이상 큰 경우(따라서 4*대상)Width < width>는 더 나은 품질을 구현하기 위해 여러 크기 조정을 사용할 수 있습니다.적어도 일반 자바에서는 작동합니다. 안드로이드에서는 http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html 확장에 사용되는 보간을 지정할 수 있는 옵션이 없습니다.
나는 다음과 같은 코드를 사용했습니다.
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를 시도하면 OutOf Memory Error가 발생합니다.
추적했지만 원래 비트맵이 너무 크면 "BitmapFactory.decodeStream(즉, null, options);"에서 OutOfMemoryError를 여전히 던집니다.
위의 코드는 조금 더 깨끗해졌습니다.InputStreams는 최종적으로 닫힘을 보장하기 위한 닫힘 랩핑(close wrapping)을 수행했습니다.
*참고
Input: InputStream은 intw, intw, intw
출력: 비트맵
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");
}
이미지를 "올바른" 방식으로 확대하려면 픽셀을 건너뛰지 않고 이미지 디코더에 연결하여 행 단위로 다운샘플링을 수행해야 합니다.Android(및 이를 기반으로 하는 Skia 라이브러리)는 이러한 후크를 제공하지 않으므로 직접 롤(roll)해야 합니다.당신이 jpeg 이미지를 말하는 것을 가정한다면, 당신의 최선의 방법은 c에서 libjpeg를 직접 사용하는 것일 것입니다.
관련된 복잡성을 고려할 때 이미지 미리보기 유형의 앱에는 2단계 하위 샘플을 사용한 후 재스케일을 사용하는 것이 가장 적합할 것입니다.
크기 조정에 다른 방법을 사용하는 기사가 있습니다.프로세스에서 사용 가능한 메모리를 기반으로 가능한 최대 비트맵을 메모리에 로드한 후 변환을 수행합니다.
http://bricolsoftconsulting.com/2012/12/07/handling-large-images-on-android/
한 단계 크기를 꼭 조정하고 싶다면 안드로이드:largeHeap = true인 경우 전체 비트맵을 로드할 수 있지만 보시다시피 권장되지 않습니다.
문서: 안드로이드: large Heap 응용프로그램의 프로세스를 큰 Dalvik 힙으로 만들어야 하는지 여부.이는 응용프로그램을 위해 작성된 모든 프로세스에 적용됩니다.프로세스에 로드된 첫 번째 응용프로그램에만 적용됩니다. 여러 응용프로그램이 프로세스를 사용할 수 있도록 공유 사용자 ID를 사용하는 경우 모든 응용프로그램이 이 옵션을 지속적으로 사용해야 합니다. 그렇지 않으면 예측할 수 없는 결과가 발생합니다.대부분의 앱은 이 기능을 필요로 하지 않아야 하며, 성능 향상을 위해 전체 메모리 사용량을 줄이는 데 중점을 두어야 합니다.일부 장치는 총 가용 메모리의 제약을 받기 때문에 이 기능을 활성화해도 사용 가능한 메모리가 고정적으로 증가하지는 않습니다.
Android 개발자 웹사이트에는 이 정확한 문제에 대한 훌륭한 기사가 있습니다.대용량 비트맵을 효율적으로 로드
저는 이게 통했어요.함수는 sd 카드의 파일에 대한 경로를 가져오고 표시 가능한 최대 크기의 비트맵을 반환합니다.코드는 Ofir에서 온 것으로, sd의 이미지 파일과 같은 일부 변경 사항이 Resource와 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;
}
}
안드로이드에서 메모리의 큰 이미지를 디코딩하는 데 문제가 없는 제가 사용하는 코드입니다.입력 파라미터가 1024x1024 정도이면 20MB보다 큰 이미지를 디코딩할 수 있습니다.반환된 비트맵을 다른 파일에 저장할 수 있습니다.이 방법 아래에는 이미지를 새 비트맵으로 스케일링하는 데 사용하는 또 다른 방법이 있습니다.당신이 원하는 대로 이 코드를 자유롭게 사용하세요.
/*****************************************************************************
* 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 calls decode 메서드를 제외하고는 서로 관계가 없습니다.노트 너비와 높이는 원래 이미지에서 변경될 수 있습니다.
/*****************************************************************************
* 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
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);
사용합니다.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)
}
다음 코드를 사용하여 비트맵 크기 조정
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
언급URL : https://stackoverflow.com/questions/3331527/resize-a-large-bitmap-file-to-scaled-output-file-on-android
'programing' 카테고리의 다른 글
스위프트에서 애니메이션에서 단순한 페이드를 만들라고요? (0) | 2023.10.23 |
---|---|
C 구조를 선언하는 구문론적으로 적절한 방법은 무엇입니까? (0) | 2023.10.23 |
on click div 속성에서 자바스크립트에서 control+click 검출하는 방법? (0) | 2023.10.23 |
WordPress 3.8: wordPress content 디렉토리(wp-content)를 찾을 수 없습니다. (0) | 2023.10.23 |
Powershell 서비스가 중지되거나 시작될 때까지 기다립니다. (0) | 2023.10.23 |