Crop bitmap issue - java

I'm using this code to crop an image:
Bitmap raw = ((BitmapDrawable)hWlp).getBitmap();
DisplayMetrics metrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager)
context.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(metrics);
int width = metrics.widthPixels;
int height = metrics.heightPixels;
wallpaper = Bitmap.createBitmap(raw, width/2, 0, width, height);
My source image (raw) is 800x960 and the target image is 800x480 (screen size). So I don't understand why I get this error:
java.lang.IllegalArgumentException: x + width must be <= bitmap.width()
if in my case x + width (480/2 + 480) is 720 and bitmap.width() is 960

You can use like that :
public static Bitmap cropAndScale (Bitmap source,int scale){
int factor = source.getHeight() <= source.getWidth() ? source.getHeight(): source.getWidth();
int longer = source.getHeight() >= source.getWidth() ? source.getHeight(): source.getWidth();
int x = source.getHeight() >= source.getWidth() ?0:(longer-factor)/2;
int y = source.getHeight() <= source.getWidth() ?0:(longer-factor)/2;
source = Bitmap.createBitmap(source, x, y, factor, factor);
source = Bitmap.createScaledBitmap(source, scale, scale, false);
return source;
}
This is example and you can change variables by displaymetrics

You can get this error only, if your app is in landscape orientation ;)
I think, in this case metrics.widthPixels can return 800px instead 480px.

Related

PDFBox set Signature to Center of the Rectangle

Using PDFBox i am try to set signature to center on the box of rectacle, assume the rectacle size is 120x60 and can be customized and image signature can vary, examples 1000*1000 or 640x320 etc. I am try with resize the signature like the box :
// save and restore graphics if the image is too large and needs to be scaled
cs.saveGraphicsState();
cs.transform(Matrix.getScaleInstance(0.85f, 0.85f));
PDImageXObject img = PDImageXObject.createFromFileByExtension(imageFile, doc);
float wpercent = (rect.getWidth() / img.getWidth());
float newHeight = img.getHeight() * wpercent;
cs.drawImage(img, 0,0, rect.getWidth(), newHeight); //Resize image signature fit to rectangle and resize the height by percent to avoid stretch image
cs.restoreGraphicsState();
try to calculate coordinate inside the box
cs.drawImage(img, rect.getWidth()*0.10,rect.getHeight()*0.10, rect.getWidth(), newHeight);
example image got success set on center image size 1880x1000
if the signature just QR size 1000x1000
the QR got cut off
how to fix that ?
Solved refers to Auto resized image
by adding this function to scale image fit to rectangle
public static Dimension getScaledDimension(Dimension imgSize, Dimension boundary) {
int original_width = imgSize.width;
int original_height = imgSize.height;
int bound_width = boundary.width;
int bound_height = boundary.height;
int new_width = original_width;
int new_height = original_height;
// first check if we need to scale width
if (original_width > bound_width) {
//scale width to fit
new_width = bound_width;
//scale height to maintain aspect ratio
new_height = (new_width * original_height) / original_width;
}
// then check if we need to scale even with the new height
if (new_height > bound_height) {
//scale height to fit instead
new_height = bound_height;
//scale width to maintain aspect ratio
new_width = (new_height * original_width) / original_height;
}
return new Dimension(new_width, new_height);
}
then add to this function
Dimension scaledDim = getScaledDimension(new Dimension(img.getWidth(), img.getHeight()), new Dimension((int)rect.getWidth(), (int)rect.getHeight()));
int x = ((int) rect.getWidth() - scaledDim.width) / 2;
int y = ((int) rect.getHeight() - scaledDim.height) / 2;
cs.drawImage(img, x, y, scaledDim.width, scaledDim.height);

Why do I get an error when saving an image?

please tell me why I get this error?
java.lang.IllegalArgumentException: x + width must be <= bitmap.width()
The error refers to the line below. An error occurs when saving the image after editing:
surfaceView = new PhotoEditor(this, bitmap, arrowArrayList);
setContentView(surfaceView);
My java code:
relativeLayoutPhoto = findViewById(R.id.relativeLayoutPhoto);
SharedPreferences sharedPreferences;
int width;
int height;
float ratioToMedium;
sharedPreferences = this.getSharedPreferences(SHARED_PREFERENCES_DISPLAY, Context.MODE_PRIVATE);
width = sharedPreferences.getInt(WIDTH_KEY, 0);
height = sharedPreferences.getInt(HEIGHT_KEY, 0);
ratioToMedium = sharedPreferences.getFloat(RATIO_TO_MEDIUM_KEY, 0);
Bitmap b = Bitmap.createScaledBitmap(bitmap, width, (int) (height - toolBarHeight * ratioToMedium),false);
Drawable drawable = new BitmapDrawable(getResources(), b);
relativeLayoutPhoto.setBackground(drawable);
relativeLayoutPhoto.setOnDragListener(this);
Can you write your bitmap width and height and also values of every argument in this method?
Bitmap b = Bitmap.createScaledBitmap(bitmap, width, (int) (height - toolBarHeight * ratioToMedium),false);

How to crop bitmap image from both top and bottom? [duplicate]

I have bitmaps which are squares or rectangles. I take the shortest side and do something like this:
int value = 0;
if (bitmap.getHeight() <= bitmap.getWidth()) {
value = bitmap.getHeight();
} else {
value = bitmap.getWidth();
}
Bitmap finalBitmap = null;
finalBitmap = Bitmap.createBitmap(bitmap, 0, 0, value, value);
Then I scale it to a 144 x 144 Bitmap using this:
Bitmap lastBitmap = null;
lastBitmap = Bitmap.createScaledBitmap(finalBitmap, 144, 144, true);
Problem is that it crops the top left corner of the original bitmap, Anyone has the code to crop the center of the bitmap?
This can be achieved with: Bitmap.createBitmap(source, x, y, width, height)
if (srcBmp.getWidth() >= srcBmp.getHeight()){
dstBmp = Bitmap.createBitmap(
srcBmp,
srcBmp.getWidth()/2 - srcBmp.getHeight()/2,
0,
srcBmp.getHeight(),
srcBmp.getHeight()
);
}else{
dstBmp = Bitmap.createBitmap(
srcBmp,
0,
srcBmp.getHeight()/2 - srcBmp.getWidth()/2,
srcBmp.getWidth(),
srcBmp.getWidth()
);
}
While most of the above answers provide a way to do this, there is already a built-in way to accomplish this and it's 1 line of code (ThumbnailUtils.extractThumbnail())
int dimension = getSquareCropDimensionForBitmap(bitmap);
bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension);
...
//I added this method because people keep asking how
//to calculate the dimensions of the bitmap...see comments below
public int getSquareCropDimensionForBitmap(Bitmap bitmap)
{
//use the smallest dimension of the image to crop to
return Math.min(bitmap.getWidth(), bitmap.getHeight());
}
If you want the bitmap object to be recycled, you can pass options that make it so:
bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
From: ThumbnailUtils Documentation
public static Bitmap extractThumbnail (Bitmap source, int width, int
height)
Added in API level 8 Creates a centered bitmap of the desired size.
Parameters source original bitmap source width targeted width
height targeted height
I was getting out of memory errors sometimes when using the accepted answer, and using ThumbnailUtils resolved those issues for me. Plus, this is much cleaner and more reusable.
Have you considered doing this from the layout.xml ? You could set for your ImageView the ScaleType to android:scaleType="centerCrop" and set the dimensions of the image in the ImageView inside the layout.xml.
You can used following code that can solve your problem.
Matrix matrix = new Matrix();
matrix.postScale(0.5f, 0.5f);
Bitmap croppedBitmap = Bitmap.createBitmap(bitmapOriginal, 100, 100,100, 100, matrix, true);
Above method do postScalling of image before cropping, so you can get best result with cropped image without getting OOM error.
For more detail you can refer this blog
Here a more complete snippet that crops out the center of an [bitmap] of arbitrary dimensions and scales the result to your desired [IMAGE_SIZE]. So you will always get a [croppedBitmap] scaled square of the image center with a fixed size. ideal for thumbnailing and such.
Its a more complete combination of the other solutions.
final int IMAGE_SIZE = 255;
boolean landscape = bitmap.getWidth() > bitmap.getHeight();
float scale_factor;
if (landscape) scale_factor = (float)IMAGE_SIZE / bitmap.getHeight();
else scale_factor = (float)IMAGE_SIZE / bitmap.getWidth();
Matrix matrix = new Matrix();
matrix.postScale(scale_factor, scale_factor);
Bitmap croppedBitmap;
if (landscape){
int start = (tempBitmap.getWidth() - tempBitmap.getHeight()) / 2;
croppedBitmap = Bitmap.createBitmap(tempBitmap, start, 0, tempBitmap.getHeight(), tempBitmap.getHeight(), matrix, true);
} else {
int start = (tempBitmap.getHeight() - tempBitmap.getWidth()) / 2;
croppedBitmap = Bitmap.createBitmap(tempBitmap, 0, start, tempBitmap.getWidth(), tempBitmap.getWidth(), matrix, true);
}
Probably the easiest solution so far:
public static Bitmap cropCenter(Bitmap bmp) {
int dimension = Math.min(bmp.getWidth(), bmp.getHeight());
return ThumbnailUtils.extractThumbnail(bmp, dimension, dimension);
}
imports:
import android.media.ThumbnailUtils;
import java.lang.Math;
import android.graphics.Bitmap;
To correct #willsteel solution:
if (landscape){
int start = (tempBitmap.getWidth() - tempBitmap.getHeight()) / 2;
croppedBitmap = Bitmap.createBitmap(tempBitmap, start, 0, tempBitmap.getHeight(), tempBitmap.getHeight(), matrix, true);
} else {
int start = (tempBitmap.getHeight() - tempBitmap.getWidth()) / 2;
croppedBitmap = Bitmap.createBitmap(tempBitmap, 0, start, tempBitmap.getWidth(), tempBitmap.getWidth(), matrix, true);
}
public Bitmap getResizedBitmap(Bitmap bm) {
int width = bm.getWidth();
int height = bm.getHeight();
int narrowSize = Math.min(width, height);
int differ = (int)Math.abs((bm.getHeight() - bm.getWidth())/2.0f);
width = (width == narrowSize) ? 0 : differ;
height = (width == 0) ? differ : 0;
Bitmap resizedBitmap = Bitmap.createBitmap(bm, width, height, narrowSize, narrowSize);
bm.recycle();
return resizedBitmap;
}
public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
if (w == size && h == size) return bitmap;
// scale the image so that the shorter side equals to the target;
// the longer side will be center-cropped.
float scale = (float) size / Math.min(w, h);
Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
int width = Math.round(scale * bitmap.getWidth());
int height = Math.round(scale * bitmap.getHeight());
Canvas canvas = new Canvas(target);
canvas.translate((size - width) / 2f, (size - height) / 2f);
canvas.scale(scale, scale);
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
canvas.drawBitmap(bitmap, 0, 0, paint);
if (recycle) bitmap.recycle();
return target;
}
private static Bitmap.Config getConfig(Bitmap bitmap) {
Bitmap.Config config = bitmap.getConfig();
if (config == null) {
config = Bitmap.Config.ARGB_8888;
}
return config;
}
val sourceWidth = source.width
val sourceHeight = source.height
val xScale = newWidth.toFloat() / sourceWidth
val yScale = newHeight.toFloat() / sourceHeight
val scale = xScale.coerceAtLeast(yScale)
val scaledWidth = scale * sourceWidth
val scaledHeight = scale * sourceHeight
val left = (newWidth - scaledWidth) / 2
val top = (newHeight - scaledHeight) / 2
val targetRect = RectF(
left, top, left + scaledWidth, top
+ scaledHeight
)
val dest = Bitmap.createBitmap(
newWidth, newHeight,
source.config
)
val mutableDest = dest.copy(source.config, true)
val canvas = Canvas(mutableDest)
canvas.drawBitmap(source, null, targetRect, null)
binding.imgView.setImageBitmap(mutableDest)

Bitmap not scaling to height Android

I have a 480 x 800 bitmap that I am using for a live wallpaper I am creating. When I test on the emulator the bitmap width and height scales fine but when I test on my Samsung S3 the bitmap width scales fine but the height is too short, shows black rectangle at the bottom. Is there a standard bitmap size I should be working with or is there something wrong in my code?:
public void doDraw(Canvas c) {
c.drawColor(Color.rgb(0,0,0)); // Clear the background.
final int canvasWidth = getScreenWidth();
final int canvasHeight = getScreenHeight();
int imageWidth = mBitmap.getWidth();
int imageHeight = mBitmap.getHeight();
float scaleFactor = Math.min( (float)canvasWidth / imageWidth,
(float)canvasHeight / imageHeight );
Bitmap scaled = Bitmap.createScaledBitmap( mBitmap,
(int)(scaleFactor * imageWidth),
(int)(scaleFactor * imageHeight),
true );
c.drawBitmap(scaled, 0, 0, null);
I think you want Math.max() instead of Math.min()

Bitmap out of range error

I'm resizing an array of Bitmaps to a certain percentage of screen (So looks the same on all devices). Some of the bitmaps are sprites with + 256kb in size (explosions etc).
Obviously the VM is running out of memory once the bitmaps are converted twice, the bitmaps only convert at the beginning of the android application but it's still giving the error.
Can anyone tell me, is there a better, faster, more effcient way to return this peice of code as a bitmap.
Just out of curiosity are bitmap values passed by reference? (As in does the object parameter use the same line of memory for the same object?).
Anyhow's here is z code:
public Bitmap ResizeBitmap(Bitmap bitmap, float s_percentage, int frames, int viewport_width, int viewport_height)
{
float percentage = s_percentage / 100.0f;
float scale = viewport_width / 100 * percentage;
if(viewport_width < viewport_height)
{
scale = viewport_height / 100 * percentage;
}
int newWidth = (int) (bitmap.getWidth() * scale);
int newHeight = (int) (bitmap.getHeight() * scale);
if(newWidth <= 0 || newHeight <= 0)
{
// Extra check, for invalid width/height
Log.e("Function List, Resize Bitmap", "invalid dimension ("+newWidth+"x"+newHeight+")");
return bitmap;
}
//Round up to closet factor of total frames
int rW = (newWidth/frames)+1;
newWidth = rW*frames;
Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, false);
return newBitmap;
}
To be in VM budget try to scale down your Bitmap like this.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile( filename, options );
options.inJustDecodeBounds = false;
options.inSampleSize = 4;
bitmap = BitmapFactory.decodeFile( filename, options );
if ( bitmap != null ) {
bitmap = Bitmap.createScaledBitmap( bitmap, width, height, false );
}
//Adjust SampleSize to values like 2, 4, 8 etc

Categories

Resources