My app uses geojson to draw features on map. To draw feature:
for (GeoJsonFeature f : new GeoJsonLayer(googleMap, new JSONObject(geojson)).getFeatures())
{
f.setPointStyle(getPointStyle(text,status);
layer.addFeature(f);
}
layer.addLayerToMap();
To generate point (marker) style and set icon:
GeoJsonPointStyle markerStyle = new GeoJsonPointStyle();
int[] markers = {R.drawable.marker0,R.drawable.marker1,R.drawable.marker2,R.drawable.marker3,R.drawable.marker4};
bmp = Utils.drawTextToBitmap(getContext(), markers[status], icon);
markerStyle.setIcon(highlighted ? BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN):BitmapDescriptorFactory.fromBitmap(bmp));
drawTextToBitmap just generates bitmap with text on it:
public static Bitmap drawTextToBitmap(Context gContext, int gResId, String gText)
{
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap = BitmapFactory.decodeResource(resources, gResId);
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
if (bitmapConfig == null)
{
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setTextSize((int) (18 * scale));
Typeface tf = Typeface.createFromAsset(gContext.getAssets(), "fonts/fontawesome.ttf");
paint.setTypeface(Typeface.create(tf, Typeface.BOLD));
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
Rect bounds = new Rect();
paint.getTextBounds(gText, 0, gText.length(), bounds);
int x = (bitmap.getWidth() - bounds.width()) / 2;
int y = (bitmap.getHeight() + bounds.height()) / 2 -8;
canvas.drawText(gText, x, y, paint);
return bitmap;
}
My problem is that on some phones (not on every phone) this approach causes huge memory leak if there is big amount of markes to draw on map. Problem does not exists if I use static marker drawable from resources, but I need dynamic bitmap to add text on it.
Do you have any idea about memory leak cause? It seems map holds bitmap reference so it prevents garbage from disposing it. Even if map fragment is destroyed, map resources will be never released, so after displaying map few times, app stops working due to OutOfMemory exception.
Related
I've got a bitmap displayed in an ImageView, and I want to be able to make a certain percentage of the image black and white, and have the other part retain it's color. For example, if 60% is the target percentage, the image would look like this: . Thanks.
I've got a bitmap displayed in an ImageView, and I want to be able to
make a certain percentage of the image black and white, and have the
other part retain it's color. For example, if 60% is the target
percentage.
It seems (from your image) you mean monochrome (i.e. greyscale), not black and white.
Something like this should do it (tested o.k.):
void doIt(ImageView image)
{
//get bitmap from your ImageView (image)
Bitmap originalBitmap = ((BitmapDrawable)image.getDrawable()).getBitmap();
int height = originalBitmap.getHeight();
int fortyPercentHeight = (int) Math.floor(height * 40.0 / 100.0);
//create a bitmap of the top 40% of image height that we will make black and white
Bitmap croppedBitmap = Bitmap.createBitmap(originalBitmap, 0, 0, originalBitmap.getWidth() , fortyPercentHeight );
//make it monochrome
Bitmap blackAndWhiteBitmap = monoChrome(croppedBitmap);
//copy the monochrome bmp (blackAndWhiteBitmap) to the original bmp (originalBitmap)
originalBitmap = overlay(originalBitmap, blackAndWhiteBitmap);
//set imageview to new bitmap
image.setImageBitmap(originalBitmap );
}
Bitmap monoChrome(Bitmap bitmap)
{
Bitmap bmpMonochrome = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmpMonochrome);
ColorMatrix ma = new ColorMatrix();
ma.setSaturation(0);
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(ma));
canvas.drawBitmap(bitmap, 0, 0, paint);
return bmpMonochrome;
}
Bitmap overlay(Bitmap bmp1, Bitmap bmp2)
{
Bitmap bmp3 = bmp1.copy(Bitmap.Config.ARGB_8888,true);//mutable copy
Canvas canvas = new Canvas(bmp3 );
canvas.drawBitmap(bmp2, new Matrix(), null);
return bmp3 ;
}
I have a requirement, like drawing something in canvas and saving it to a larger image. As of now whatever I draw inside onDraw() method and save, it gives device provided image/canvas size, say something around 538(w)/852(h). I need image of almost double size, around 1000(w)/1500(h) without losing resolution. Any sample code, reference link would help definitely. Thanks in advance.
One way is to create Bitmap of desired size and draw on it using canvas:
int w = 1000, h = 1500;
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
Bitmap bmp = Bitmap.createBitmap(w, h, conf);
Canvas canvas = new Canvas(bmp);
Finally you will have you bmp with your drawing and necessary dimentions.
EDIT::
#Override
protected void onDraw(Canvas canvas) {
int w = 1000, h = 1500;
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
Bitmap bmp = Bitmap.createBitmap(w, h, conf);
Canvas mycanvas = new Canvas(bmp);
super.onDraw(mycanvas);
...
}
First get bitmap of your view using the function getDrawingCache(), then scale the bitmap as per your requirements.
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
//bitmap = bitmap.createScaledBitmap(..as your requirements..);
EDIT
You are saying that you want image in higher quality. You can't simply get a higher quality image from a lower quality image. However you can apply bitmap filtering to get slightly better quality.
Bitmap bitmap = getDrawingCache();
Bitmap output = Bitmap.createBitmap(/*width, height, bla bla bla*/);
Canvas canvas = new Canvas(output);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
Rect srcRect = new Rect(0,0,bitmap.getWidth(), bitmap.getHeight());
Rect destRect = new Rect(0,0,output.getWidth(), output.getHeight());
canvas.drawBitmap(bitmap, srcRect, destRect, paint);
for my app I am creating an image editor which currently works fine but I want to implement un undo button which basically goes back to the previous state of the image. I am trying to do this by using an ArrayList of bitmaps. At first I use this code to open an image from gallery and set canvas:
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(
imageFileUri), null, bmpFactoryOptions);
bmpFactoryOptions.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(
imageFileUri), null, bmpFactoryOptions);
alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp
.getHeight(), bmp.getConfig());
int x = alteredBitmap.getWidth();
int y = alteredBitmap.getHeight();
if (x > y) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
lscape = true;
} else {
lscape = false;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
width = size.x;
height = size.y;
paint = new Paint();
paint.setColor(Color.GREEN);
paint.setStrokeWidth(5);
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint.setStyle(Paint.Style.FILL);
String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
Cursor cur = managedQuery(imageFileUri, orientationColumn, null, null, null);
int orientation = -1;
if (cur != null && cur.moveToFirst()) {
orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
}
Matrix matrix = new Matrix();
if (orientation!=90) {
matrix.postRotate(orientation);
scaledBitmap = Bitmap.createScaledBitmap(alteredBitmap, width, height, false);
canvas = new Canvas(scaledBitmap);
canvas.drawBitmap(bmp, matrix, paint);
choosenImage.setImageBitmap(scaledBitmap);
choosenImage.setOnTouchListener(this);
b.add(scaledBitmap);
}
At some point of code I use this to draw a straight line:
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downx = event.getX();
downy = event.getY();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
upx = event.getX();
upy = event.getY();
canvas.drawLine(getScaledWidth(downx, width, choosenImage.getWidth()), downy / choosenImage.getHeight() * height, getScaledWidth(upx, width, choosenImage.getWidth()), upy / choosenImage.getHeight() * height, paint);
choosenImage.invalidate();
b.add(scaledBitmap);
break;
case MotionEvent.ACTION_CANCEL:
break;
default:
break;
}
Now what should I write for my onclick on undo button? I've tried everything but dont know how to reset the canvas to display one of the bitmaps saved in the arraylist...dont know if its a problem with my way of setting the canvas to the bitmaps or if im missing something. This was my latest attempt:
scaledBitmap = b.get(b.size()-2);
b.remove(b.size() - 1);
choosenImage.invalidate();
Im new to android development so sorry if I'm not being clear, but really any help would be greatly appreciated I am stuck in this project and it is due in soon.
Thanks in advance!
List of bitmaps --> Out of memory!
Bitmaps are kept in a very limited area of memory and having a whole list of fullscreen bitmaps for und purposes will make your app go out of memory very quickly.
List of paths --> Better
What I did for my (very old) app "Fingercolors", is keeping a list of all paths the user paints. The paths consist of a list of points and some information about color, stroke-width etc.
For undoing a step, I start (offscreen) with an empty bitmap and repaint all paths from the list except for the last one and then show that rebuilt bitmap.
This allows unlimited undo and also redo and it is fast enough even for complex images with lots of paths.
I have a problem with a function that I implemented. On some phones I get a out of memory error.
private Bitmap getIconMarkerOfPlayer(Player p) {
Drawable drawable = getIconOfPlayer(p);
Bitmap img = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(img);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
final float scale = this.getResources().getDisplayMetrics().density;
int heigthPixels = (int) (24 * scale + 0.5f);
int widthPixels = (int) (24 * scale + 0.5f);
return Bitmap.createScaledBitmap(img, widthPixels, heigthPixels, false);
}
The getIconMarkerOfPlayer(Player p) function gives a "programmed" drawable depending on the player's status (dead, alive, offline, ...) and its color. Each player has a unique color assigned to it in the early games.
How can I resize my bitmap from a Drawable object without having a out of memory error?
I suggest you to use some ImageLibraries to load Bitmaps efficiently.
Some of them are Fresco, Glide, Piccasio.
I suggest you to go with Glide. Have a look at it here
I have a requirement where I will be having a background Image and one mask Image. Lets say the background Image is of Motorcycle and the mask will be used to hide the registration number. So the mask will be movable and also resize-able. Finally the combined Image will be generated with background image and Image mask. How we can achieve this ?
public Bitmap drawFacesOnBitmap(Context gContext, Bitmap bitmap) {
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialised Paint
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.GREEN);
// draw text to the Canvas center
Log.d("BITMAP DIMENS****", "bitmapWidth:"+bitmap.getWidth()+" & bitmapHeight:"+bitmap.getHeight());
android.graphics.Rect r = new android.graphics.Rect();
r.left = 200;
r.top = 200;
r.right = 400;
r.bottom = 400;
canvas.drawRect(r, paint);
return bitmap;
}
You can use this code to draw a rectangle on a bitmap. Edit it to meet your needs.