Does anyone have a hint or explanation for the following problem ?
I draw a path with a bitmapshader. When canvas is not scaled, it looks good ( first picture ).
When I scale into ( zooming in ) the bitmapshader is not be scaled and looks very ugly. I tried several things with recreating the bitmapshader after zooming in, but did not succeed :-(. Does anyone have a hint ?
No Scaling it looks good :
when scaling it looks ugly:
Code :
canvas.scale(scalex, scaley);
canvas.translate(itranslatex, itranslatey);
fillBMP = makePatternCross(fscalex, 1, Color.GREEN/*,fscalex,fscaley*/);
fillBMPshader = new BitmapShader(fillBMP, BitmapShader.TileMode.REPEAT, BitmapShader.TileMode.REPEAT);
paintshader = new Paint();
paintshader.setShader(fillBMPshader);
canvas.drawPath(cpath.path, paintshader);
private static Bitmap makePatternCross(float fSize, float fStrokewith,int iColor) {
Log.v("Create Patter makePatternCross","makePatternCross");
float fBitmapSizeOrig = 10;
fBitmapSizeOrig=fBitmapSizeOrig*fSize;
Bitmap bm = Bitmap.createBitmap((int)fBitmapSizeOrig,(int) fBitmapSizeOrig,Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
//c.scale(200, 200);
c.drawColor(Color.WHITE);
Paint p = new Paint();
p.setColor(iColor);
//p.setStrokeWidth(iStrokewith);
p.setStrokeWidth(fStrokewith/fSize);
p.setStrokeWidth((float) 0.000001);
c.drawLine(0, 0, fBitmapSizeOrig, fBitmapSizeOrig, p);
c.drawLine(0, fBitmapSizeOrig, fBitmapSizeOrig, 0, p);
if (fSize != 1) {
int iNewSize = (int) (( fBitmapSizeOrig) * fSize);
bm = Bitmap.createScaledBitmap(bm, iNewSize, iNewSize, false);
}
int width = bm.getWidth();
int height = bm.getHeight();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (bm.getPixel(x, y) == Color.WHITE) {
bm.setPixel(x, y, Color.TRANSPARENT);
} else {
// bm.setPixel(x, y, bm.getPixel(x, y));
}
}
}
return bm;
}
Not sure exactly if this is what your looking for. But if you use a matrix to scale the bitmap it retains more quality than normal scaling.
Matrix matrix = new Matrix();
matrix.postScale(desiredScale, desiredScale);
Bitmap scaledBitmap = Bitmap.createBitmap(sampledSrcBitmap, 0, 0, sampledSrcBitmap.getWidth(), sampledSrcBitmap.getHeight(), matrix, true);
Also when going from a lesser resolution to a higher you can try this as well:
Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap source = BitmapFactory.decodeResource(a.getResources(), path, options);
Related
I am trying to draw a avatar bitmap using this code. But the bitmap is pixelated. Here is my Code. Currently I use createScaledBitmap to resize the avatar image. Also the Text are a little smaller on some devices with a high resolution
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.card_nodpi, opt) ;
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(40);
paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
canvas.drawText("The quick brown fox", x, y, paint);
Paint paint2 = new Paint();
paint2.setColor(Color.BLACK);
paint2.setTextSize(30);
canvas.drawText("The quick brown fox", x, y + (40), paint2);
canvas.drawText("The quick brown fox", x, y + ((40 * 2)), paint2);
if (avatar != null) {
Bitmap img = Bitmap.createScaledBitmap(avatar, 250, 250, false);
canvas.drawBitmap(img, bitmap.getWidth() - img.getWidth() - x, y - 40, new Paint(Paint.FILTER_BITMAP_FLAG));
}
imageView.setImageBitmap(bitmap);
createScaledBitmap can produce some funky/bad quality images.
Try out this solution here:
https://stackoverflow.com/a/7468636/4557530
Let me know if that does anything for you!
Alternatively,
try this, I used this code before thanks to some blog, which I don't remember anymore
Bitmap newBM = Bitmap.createBitmap(newWidth, newHeight, Config.ARGB_8888);
float scaleX = newWidth / (float) origBM.getWidth();
float scaleY = newHeight / (float) origBM.getHeight();
float pivX = 0;
float pivY = 0;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY);
Canvas canvas = new Canvas(newBM);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(origBM, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG));
When calling the following method:
Bitmap localBitmap = Bitmap.createScaledBitmap(paramBitmap, 360, (int)(360.0D / (paramBitmap.getWidth() / paramBitmap.getHeight())), false);
I get the exception trace as:
java.lang.IllegalArgumentException: bitmap size exceeds 32 bits
I printed the size of incoming bitmap using statements:
System.out.println("paramBitmap.getWidth() "+ paramBitmap.getWidth());
System.out.println("paramBitmap.getHeight() "+ paramBitmap.getHeight());
and it is 480x960
How to debug this problem and solve it.
i know its late but it might help somebody,I faced the same problem when i tried to draw a border for bitmap and rotate it to certain angle, it always crashed in xiaomi mi mobile, i solved it by scaling the bitmap as per the need,
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bmp = BitmapFactory.decodeFile(path, options);
final int BORDER_WIDTH = 10;
final int BORDER_COLOR = Color.YELLOW;
Bitmap res = Bitmap.createBitmap(bmp.getWidth() + 2 * BORDER_WIDTH,bmp.getHeight() + 2 * BORDER_WIDTH,bmp.getConfig());
Canvas c = new Canvas(res);
Paint p = new Paint();
p.setColor(BORDER_COLOR);
c.drawRect(0, 0, res.getWidth(), res.getHeight(), p);
p = new Paint(Paint.FILTER_BITMAP_FLAG);
c.drawBitmap(bmp, BORDER_WIDTH, BORDER_WIDTH, p);
float viewWidth = (float) res.getWidth();
float viewHeight = `enter code here`(float) res.getHeight();
float ratiowidth = vi`enter code here`ewWidth / (float) res.getWidth();
float ratioheight = viewHeight / (float) res.getHeight();
Matrix mat = new Matrix();
mat.postScale(ratiowidth, ratioheight);
mat.postRotate(45);
Bitmap bMapRotate = Bitmap.createBitmap(res, 0,0,res.getWidth(),res.getHeight(), mat, true);
I have got images which I want to slice into 10 pieces vertically of equal height so on hdpi slice dimensions are 800*48 (landscape application). I have got following code which is not working
public void convertBitmapinSlices(){
Bitmap tempBitmap;
try{
Paint paint = new Paint();
paint.setFilterBitmap(true);
tempBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img1);
int targetWidth = (int) Methods.dpToPx(tempBitmap.getWidth(), this);
Log.v("TARGET_WIDTH", Integer.toString(targetWidth));
int targetHeight = (int) (Methods.dpToPx(tempBitmap.getHeight(), this)/10);
Log.v("TARGET_HEIGHT", Integer.toString(targetHeight));
Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, targetHeight,Bitmap.Config.ARGB_8888);
RectF rectf = new RectF(0, 0, targetWidth, targetHeight);
Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
path.addRect(rectf, Path.Direction.CW);
canvas.clipPath(path);
int starty=0;
lLforGardenImages.removeAllViews();
for(int i=1; i<=10;i++){
Log.v("SRC-Height", Integer.toString(targetHeight*i));
Log.v("START-Y", Integer.toString(starty));
canvas.drawBitmap(tempBitmap, new Rect(0, starty, tempBitmap.getWidth(), (tempBitmap.getHeight()/10)+starty),
new Rect(0, 0, targetWidth,targetHeight), paint);
// Matrix matrix = new Matrix();
// matrix.postScale(1f, 1f);
Bitmap resizedBitmap = Bitmap.createBitmap(targetBitmap, 0, 0, targetWidth, targetHeight, null, true);
Log.v("Width after Resizing ", resizedBitmap.getWidth()+"");
Log.v("Height after Resizing ", resizedBitmap.getHeight()+"");
BitmapDrawable bd = new BitmapDrawable(resizedBitmap);
ImageView iv = new ImageView(this);
iv.setAdjustViewBounds(true);
iv.setBackgroundDrawable(bd);
lLforGardenImages.addView(iv, llayoutParams);
if((i % 2) == 0){
iv.startAnimation(sliderAnimation(-1.0f,0.0f,0.0f,0.0f,1000));
}else{
iv.startAnimation(sliderAnimation(1.0f,0.0f,0.0f,0.0f,1000));
}
starty= starty+targetHeight;
}
}
catch(Exception e){
System.out.println("Error1 : " + e.getMessage() + e.toString());
}
}
Any idea what I am doing wrong?
Output is that slice is not correct and have contents which seems to have smaller height but height of slice is correct i.e 48 and width is correct too. So only issue with above code is that contents height seems to be incorrect even though slice height is correct.
I want to Rotate Image according to a specific angle in android ,some thing like a compass...
I have this code...it works on drawPath()
but i want to replace the path and the Drawing thing with image..
I tried to create a bitmap image ,DrawBitmapImage , but the image does not Rotate like the path..Any Help PLease?
public void draw(Canvas canvas) {
double angle = calculateAngle(currentLongitude, currentLatitude, targetLongitude, targetLatitude);
//Correction;
angle-=90;
//Correction for azimuth
angle-=azimuth;
if((getContext() instanceof Activity) && ((Activity)getContext()).getWindowManager().getDefaultDisplay().getOrientation()==Configuration.ORIENTATION_PORTRAIT)angle-=90;
while(angle<0)angle=angle+360;
Rect rect = canvas.getClipBounds();
int height = rect.bottom-rect.top;
int width = rect.right-rect.left;
int left = rect.left;
int top = rect.top;
if(height>width){
top+=(height-width)/2;
height=width;
}
if(width>height){
left+=(width-height)/2;
width=height;
}
float centerwidth = width/2f;
float centerheight = height/2f;
Paint p = new Paint();
p.setColor(color);
p.setStyle(Paint.Style.FILL);
p.setAntiAlias(true);
float startX = left+(float)(centerwidth+Math.cos(deg2rad(angle))*width/3.0);
float startY = top+(float)(centerheight+Math.sin(deg2rad(angle))*height/3.0);
Path path = new Path();
path.moveTo(
startX,
startY);
path.lineTo(
left+(float)(centerwidth+Math.cos(deg2rad(angle+140))*width/4.0),
top+(float)(centerheight+Math.sin(deg2rad(angle+140))*height/4.0));
path.lineTo(
left+(float)centerwidth,
top+(float)centerheight
);
path.lineTo(
left+(float)(centerwidth+Math.cos(deg2rad(angle+220))*width/4.0),
top+(float)(centerheight+Math.sin(deg2rad(angle+220))*height/4.0)
);
path.lineTo(
startX,
startY
);
canvas.drawPath(path, p);
}
You can either rotate your bitmap when you draw it by using a matrix:
Matrix matrix = new Matrix();
matrix.setRotate(angle, imageCenterX, imageCenterY);
yourCanvas.drawBitmap(yourBitmap, matrix, null);
You can also do it by rotating the canvas before drawing:
yourCanvas.save(Canvas.MATRIX_SAVE_FLAG); //Saving the canvas and later restoring it so only this image will be rotated.
yourCanvas.rotate(-angle);
yourCanvas.drawBitmap(yourBitmap, left, top, null);
yourCanvas.restore();
Pick the one that suits you the best.
You have to rotate the canvas first and then draw whatever you want. Then the object drawn will be appeared as rotated on screen.
canvas.rotate(45); // degrees to rotate
try this its good way.
Check this tutorial you will get information about how to draw bitmap and how to rotate canvas
Check complete tutorial
This is the only one that worked for me with no problem.
private Bitmap rotateBitmap(Bitmap bitmap, int rotationAngleDegree){
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int
newW=w, newH=h;
if (rotationAngleDegree==90 || rotationAngleDegree==270){
newW = h;
newH = w;
}
Bitmap rotatedBitmap = Bitmap.createBitmap(newW,newH, bitmap.getConfig());
Canvas canvas = new Canvas(rotatedBitmap);
Rect rect = new Rect(0,0,newW, newH);
Matrix matrix = new Matrix();
float px = rect.exactCenterX();
float py = rect.exactCenterY();
matrix.postTranslate(-bitmap.getWidth()/2, -bitmap.getHeight()/2);
matrix.postRotate(rotationAngleDegree);
matrix.postTranslate(px, py);
canvas.drawBitmap(bitmap, matrix, new Paint( Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG ));
matrix.reset();
return rotatedBitmap;
}
Based on #Sakthi 's code, but add scaling :)
Rect rect = new Rect(0,0,canvas.getWidth(), canvas.getHeight());
Matrix matrix = new Matrix();
matrix.postTranslate(-bitmap.getWidth()/2, -bitmap.getHeight()/2);
matrix.postScale(
((float)rect.width()) / bitmap.getWidth(),
((float)rect.height()) / bitmap.getHeight());
matrix.postRotate(180);
matrix.postTranslate(rect.exactCenterX(), rect.exactCenterY());
canvas.drawBitmap(bitmap, matrix, null);
#Reham: Look at this example code below,
public class bitmaptest extends Activity {
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
LinearLayout linLayout = new LinearLayout(this);
// load the origial BitMap (500 x 500 px)
Bitmap bitmapOrg = BitmapFactory.decodeResource(getResources(),
R.drawable.android);
int width = bitmapOrg.width();
int height = bitmapOrg.height();
int newWidth = 200;
int newHeight = 200;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// createa matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// rotate the Bitmap
matrix.postRotate(45);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
width, height, matrix, true);
// make a Drawable from Bitmap to allow to set the BitMap
// to the ImageView, ImageButton or what ever
BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
ImageView imageView = new ImageView(this);
// set the Drawable on the ImageView
imageView.setImageDrawable(bmd);
// center the Image
imageView.setScaleType(ScaleType.CENTER);
// add ImageView to the Layout
linLayout.addView(imageView,
new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT
)
);
// set LinearLayout as ContentView
setContentView(linLayout);
}
}
you have to use the matrix to rotate image look the lines
matrix.postRotate(45); -
this will rotate the image to 45 degrees
Hope this help you ...thx
Use following code. it worked for me
float rotation = 30.0f;
Bitmap bitmap = your bitmap
Rect rect = new Rect(100,100,bitmap.width, bitmap.height);
Matrix matrix = new Matrix();
float px = rect.exactCenterX();
float py = rect.exactCenterY();
matrix.postTranslate(-bitmap.getWidth()/2, -bitmap.getHeight()/2);
matrix.postRotate(rotation);
matrix.postTranslate(px, py);
canvas.drawBitmap(bitmap, matrix, null);
matrix.reset();
invalidate();
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)