I have one image (sprite) that contains two images (selected icon and non selected icon). The width of image is same but its height is double because of second image. How can I get these two images separately from one image?
I have solved this with this piece of code:
private Bitmap getCroppedBitmap(boolean isSelected){
Bitmap fullImage = BitmapFactory.decodeResource(getResources(), R.drawable.sprite);
Bitmap piece = null;
int height = fullImage.getHeight()/2;
if(isSelected){
// show first image
piece = Bitmap.createBitmap(fullImage, 0, 0, fullImage.getWidth(), height);
}else{
// show second image
piece = Bitmap.createBitmap(fullImage, 0, height, fullImage.getWidth(), height);
}
return piece;
}
Related
Context & Goal
I'm building a real-time object detection app. To achieve this, I need a bitmap to send to the recognition algorithm. I have an activity displaying the camera output in full screen, but I'm trying to operate the recognition only on the central square of the screen. So I need a bitmap with those dimensions and position, corresponding to the the central square of the phone screen.
What I have tried
#Override
public void onPreviewSizeChosen(final Size size, final int rotation) {
/* some code... */
// Width of the screen (larger than the height), for my phone it's 4032
previewWidth = size.getWidth();
// Height of the screen, for my phone it's 1980
previewHeight = size.getHeight();
sensorOrientation = rotation - getScreenOrientation();
// The bitmap which will be used to the recognition, dimension : full screen of the phone
rgbFrameBitmap = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888);
// squared bitmap 320x320, required size for the recognition algorithm
croppedBitmap = Bitmap.createBitmap(cropSize, cropSize, Config.ARGB_8888);
// bitmap to croppedBitmap transform Matrix
frameToCropTransform =
ImageUtils.getTransformationMatrix(
previewWidth, previewHeight,
cropSize, cropSize,
sensorOrientation, MAINTAIN_ASPECT);
cropToFrameTransform = new Matrix();
frameToCropTransform.invert(cropToFrameTransform);
trackingOverlay = (OverlayView) findViewById(R.id.tracking_overlay);
trackingOverlay.addCallback(
new DrawCallback() {
#Override
public void drawCallback(final Canvas canvas) {
tracker.draw(canvas, isDebug());
}
});
tracker.setFrameConfiguration(previewWidth, previewHeight, sensorOrientation);
}
#Override
protected void processImage() {
trackingOverlay.postInvalidate();
if (computingDetection) {
readyForNextImage();
return;
}
computingDetection = true;
// THE LINE I CAN'T FIGURE OUT
// I try to set width and height = previewHeight (1980 for my phone so a square)
// and to move it down by (previewWidth-previewHeight)/2 so it goes in the middle of the screen
rgbFrameBitmap.setPixels(getRgbBytes(), 0, previewWidth, 0, (previewWidth-previewHeight)/2, previewHeight, previewHeight);
readyForNextImage();
final Canvas canvas = new Canvas(croppedBitmap);
canvas.drawBitmap(rgbFrameBitmap, frameToCropTransform, null);
// Saved set to true, so I can check what the bitmap sent to the recognition algorithm looks like
if (SAVE_PREVIEW_BITMAP) {
ImageUtils.saveBitmap(croppedBitmap);
}
runInBackground(
new Runnable() {
#Override
public void run() {
// Here we send the bitmap to the recognition algorithm to perform real-time detection
final List<Classifier.Recognition> results = detector.recognizeImage(croppedBitmap);
/* some code ... */
}
If I replace the (previewWidth-previewHeight)/2 by 0 as the y parameter of rgbFrameBitmap.setPixels() function, I manage to perform real-time recognition in a square on top of the screen, as I want unless it's not centered. But as soon as I set the y parameter to (previewWidth-previewHeight)/2, this is the error I get when it tries to save the bitmap :
W/ImageReader_JNI: Unable to acquire a buffer item, very likely client tried to acquire more than maxImages buffers
How can I get the bitmap to be centered in the middle of the screen ?
Self solved
There are two thing I misunderstood on the above code.
First, I mixed up the x and the y parameters of the rgbFrameBitmap.setPixels() function, but in any case this was just adding some black space to the bitmap. To obtain the center of the screen, the parameter to change is the offset, like this :
int x = (previewWidth-previewHeight)/2;
rgbFrameBitmap.setPixels(getRgbBytes(), x, previewWidth, 0, 0, previewHeight, previewHeight);
Besides, as we send the croppedBitmap to the recognition algorithm, which is the rgbFrameBitmap cropped to 320x320 thanks to the matrix frameToCropTransform, I had to update this :
frameToCropTransform =
ImageUtils.getTransformationMatrix(
previewWidth, previewHeight,
cropSize, cropSize,
sensorOrientation, MAINTAIN_ASPECT);
into this :
frameToCropTransform =
ImageUtils.getTransformationMatrix(
previewHeight, previewHeight,
cropSize, cropSize,
sensorOrientation, MAINTAIN_ASPECT);
as rgbFrameBitmap is now a square of dimensions previewHeightxpreviewHeight
Horizontal Screen
To get the central square area of a screen, compare height and width of the screen in pixels. Usually for desktop systems width is bigger, and I will assume this is the case.
Get the difference width-height, divide by two and call it x.
Finally draw a rectangle from (x, 0) to (x+height, height).
More General
The side length of the square will be length = min(width,height)
The coordinates of the square will be
x = (width-length)/2
y = (height-length)/2
Finally draw a rectangle from (x, y) to (x+length, y+length).
I have transparent images like shapes,letters which I'm fetch from gallery so I need to give them stroke/outline with black color, I can set border but It's set to whole bitmap like left,right,top and bottom.
Same thing we can do with photoshop is giving outerstroke to image but I want to achieve that in android.
I tried this and this It's give border, But what I want to do is like below
sample image
Original Image
I want like this -->
Does this possible in android?
I have an temporary solution like this
int strokeWidth = 8;
Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.flower_icon);
Bitmap newStrokedBitmap = Bitmap.createBitmap(originalBitmap.getWidth() + 2 * strokeWidth, originalBitmap.getHeight() + 2 * strokeWidth, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newStrokedBitmap);
float scaleX = newStrokedBitmap.getWidth() / originalBitmap.getWidth();
float scaleY = newStrokedBitmap.getHeight() / originalBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY);
canvas.drawBitmap(originalBitmap, matrix, null);
canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_ATOP); //Color.WHITE is stroke color
canvas.drawBitmap(originalBitmap, strokeWidth, strokeWidth, null);
Firstly create a new bitmap with stroke size on left, right, bottom and top.
Secondly a little bit scale bitmap and draw scaled bitmap on newly created bitmap canvas.
Draw a color (your stroke color) with PorterDuff mode SRC_ATOP override original bitmap position with stroke color.
Finally draw your original bitmap on newly create bitmap canvas.
Situation: I have a picture and user could add texts on it, change there color, size, position, rotation, font size and etc., i need to save all this texts in one image. It's ok, i'm saving them by using drawing cache.
//RelativeLayout layout - layout with textviews
layout.setDrawingCacheEnabled(true);
Bitmap bitmap = null;
if (layout.getDrawingCache() != null)
bitmap = Bitmap.createBitmap(layout.getDrawingCache());
layout.setDrawingCacheEnabled(false);
Problem: Result image could be small due to screen size of the user's device. I need this image in resolution of 1500-2000 px. In case of just resizing this image - text looks fuzzy and not as good as it was on the screen.
Question: Is there're some other ways to save textviews as image without just resizing and loosing quality of text?
Ok, finally i found working solution.
The idea: user add text view on the image with 800x800 px size, do something with it and then i need to get the same image but in 2000x2000 px. The problem was - after resizing text was fuzzy and noisy. But how can i take a screenshot of not rendered view with size bigger than screen?
Here code that i used, it works just fine, i get the same image, text in the same positions, same size and etc. but no resizing noise, text look clear and not fuzzy. Also, this code save bitmap much bigger than screen size and without showing it to user.
private Bitmap makeTextLayer(int maxWidth, int maxHeight, ImageObject imageObject) {
Context c = mContext;
View v = LayoutInflater.from(c).inflate(R.layout.text_view_generator, new LinearLayout(c), false);
RelativeLayout editTexts = (RelativeLayout) v.findViewById(R.id.editTexts);
initView(v, maxWidth, maxHeight);
for (int i = 0; i < imageObject.getEditTexts().size(); ++i) {
ImageObject.TextInImage textInImage = imageObject.getEditTexts().get(i);
//text view in relative layout - init his size, in my case it's as big as image
CustomEditText editText = new CustomEditText(c);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
// don't forget to add your view to layout, this view will be saved as screenshot
editTexts.addView(editText, params);
editText.getLayoutParams().width = maxWidth;
editText.getLayoutParams().height = maxHeight;
editText.loadTextParams(textInImage);
editText.loadSizeAndRotation(textInImage);
// this is important, without new init - position of text will be wrong
initView(v, maxWidth, maxHeight);
// and here i configure position
editText.loadPosition();
}
Bitmap result = getViewBitmap(v, maxWidth, maxHeight);
return result;
}
Bitmap getViewBitmap(View v, int maxWidth, int maxHeight) {
//Get the dimensions of the view so we can re-layout the view at its current size
//and create a bitmap of the same size
int width = v.getWidth();
int height = v.getHeight();
int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
//Cause the view to re-layout
v.measure(measuredWidth, measuredHeight);
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
//Create a bitmap backed Canvas to draw the view into
Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
//Now that the view is laid out and we have a canvas, ask the view to draw itself into the canvas
v.draw(c);
return b;
}
private void initView(View view, int maxWidth, int maxHeight){
ViewGroup.LayoutParams vParams = view.getLayoutParams();
//If the View hasn't been attached to a layout, or had LayoutParams set
//return null, or handle this case however you want
if (vParams == null) {
return;
}
int wSpec = measureSpecFromDimension(vParams.width, maxWidth);
int hSpec = measureSpecFromDimension(vParams.height, maxHeight);
view.measure(wSpec, hSpec);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
//Cannot make a zero-width or zero-height bitmap
if (width == 0 || height == 0) {
return;
}
view.layout(0, 0, width, height);
}
private int measureSpecFromDimension(int dimension, int maxDimension) {
switch (dimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
return View.MeasureSpec.makeMeasureSpec(maxDimension, View.MeasureSpec.EXACTLY);
case ViewGroup.LayoutParams.WRAP_CONTENT:
return View.MeasureSpec.makeMeasureSpec(maxDimension, View.MeasureSpec.AT_MOST);
default:
return View.MeasureSpec.makeMeasureSpec(dimension, View.MeasureSpec.EXACTLY);
}
}
I would like to thank the authors of the comments in these posts:
Converting a view to Bitmap without displaying it in Android?
Taking a "screenshot" of a specific layout in Android
Take a screenshot of a whole View
Capture whole scrollview bigger than screen
How to screenshot or snapshot a view before it's rendered?
I found my solution when read them, if my solution will not work for you - check out this posts.
I have a two image one image is containing body without face and one image contain with face only...
now i want to merge this two images.... the first image which contain only body without face is in that the face is transparent.....
so how can i detect that transparent area and place face over there in transparent area
i am combining two images with below code.. but it is not proper way to place face over transparent area
below is my code
public Bitmap combineImages(Bitmap c, Bitmap s) {
Bitmap cs = null;
int width, height = 0;
if (c.getWidth() > s.getWidth()) {
width = c.getWidth() + s.getWidth();
height = c.getHeight();
} else {
width = s.getWidth() + s.getWidth();
height = c.getHeight();
}
cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(c, 0f, 0f, null);
comboImage.drawBitmap(s, 0f, 0f, null);
return cs;
}
Do you mean the face area of the body image is transparent? I.e. the alpha value in some part of the body image is low?
The following code defines my Bitmap:
Resources res = context.getResources();
mBackground = BitmapFactory.decodeResource(res, R.drawable.background);
// scale bitmap
int h = 800; // height in pixels
int w = 480; // width in pixels
// Make sure w and h are in the correct order
Bitmap scaled = Bitmap.createScaledBitmap(mBackground, w, h, true);
... And the following code is used to execute/draw it (the unscaled Bitmap):
canvas.drawBitmap(mBackground, 0, 0, null);
My question is, how might I set it to draw the scaled Bitmap returned in the form of Bitmap scaled, and not the original?
Define a new class member variable:
Bitmap mScaledBackground;
Then, assign your newly created scaled bitmap to it:
mScaledBackground = scaled;
Then, call in your draw method:
canvas.drawBitmap(mScaledBackground, 0, 0, null);
Note that it is not a good idea to hard-code screen size in the way you did in your snippet above. Better would be to fetch your device screen size in the following way:
int width = getWindowManager().getDefaultDisplay().getWidth();
int height = getWindowManager().getDefaultDisplay().getHeight();
And it would be probably better not to declare a new bitmap for the only purpose of drawing your original background in a scaled way. Bitmaps consume a lot of precious resources, and usually a phone is limited to a few MB of Bitmaps you can load before your app ungracefully fails. Instead you could do something like this:
Rect src = new Rect(0, 0, bitmap.getWidth() - 1, bitmap.getHeight() - 1);
Rect dest = new Rect(0, 0, width - 1, height - 1);
canvas.drawBitmap(mBackground, src, dest, null);
To draw the scaled bitmap you want save your scaled bitmap in a field somewhere (here called mScaled) and call:
canvas.drawBitmap(mScaled, 0, 0, null);
in your draw method (or wherever you call it right now).