Currently i'm making a photo editor app. I have activity where you can add a text to the image. I need to save image with text in bitmap. I've already tried to save drawing cache, but the problem is that it saves image in bad quality. Original image 4032*3024 when i save it uses size of imageview which are 1517 * 1137. I've tried to scale bitmap up to original size but quality is too bad. Now i'm trying to draw original bitmap on canvas then to draw text on same position as it was on View.
float x = editText.getLeft() * (scale);
float y = editText.getTop() * (scale);
canvas.drawText(editText.getText().toString(), x, y, tp);
But for some reason text is not on the same place. I've tried using density to get coordinates but it also don't works.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/add_text_color_picker_relative_layout"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true">
<RelativeLayout
android:id="#+id/edit_photo_add_text_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<ImageView
android:id="#+id/edit_photo_add_text_main_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:adjustViewBounds="true"
android:scaleType="fitCenter" />
<EditText
android:id="#+id/edit_photo_add_text_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/rect_edittext"
android:hint="Поле для текста"
android:inputType="textNoSuggestions"
android:padding="4dp"
android:textSize="14dp" />
</RelativeLayout>
</RelativeLayout>
And here is java code:
public Bitmap createImage(View view, int imageViewId, int textViewId, Context context){
ImageView imageView = (ImageView) view.findViewById(imageViewId);
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
float bitmapRatio = (bitmap.getWidth()) / bitmap.getHeight();
float imageViewRatio = (imageView.getWidth()) / imageView.getHeight();
float scaleW = bitmap.getWidth() / imageView.getWidth();
float scaleH = bitmap.getHeight() / imageView.getHeight();
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
bitmap = bitmap.copy(bitmapConfig, true);
EditText editText = (EditText) view.findViewById(textViewId);
float density = context.getResources().getDisplayMetrics().density;
Canvas canvas = new Canvas(bitmap);
canvas.setBitmap(bitmap);
TextPaint tp = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
tp.setColor(Color.WHITE);
tp.setTextSize(editText.getTextSize()*density);
Resources resources = context.getResources();
float scale = resources.getDisplayMetrics().density;
int[] xy = {0, 0};
editText.getLocationOnScreen(xy);
float x = xy[0] * (scaleW);
float y = xy[1] * (scaleH);
canvas.drawText(editText.getText().toString(), x, y, tp);
canvas.save();
canvas.restore();
return bitmap; }
editText.getLeft() and editText.getTop() gives coordinates relative to their parent while canvas.drawText() takes absolute coordinates (with respect to root) as argument.
You should take absolute coordinates of editText (with respect to the root element in your hierarchy). To find out absolute view coordinates, you can use view.getLocationOnScreen() or view.getLocationInWindow(). Thanks.
Finally I've found the solution.
When i'm calculating screen scale
float scaleW = bitmap.getWidth() / imageView.getWidth();
I'm dividing to integers and receiving wrong value;
Instead of it there should be
float scaleW = (float)bitmap.getWidth() / (float)imageView.getWidth();
and then you can draw at right position of canvas.
Related
I have a frame layout with a background image.I am using canvas to draw lines on this framelayout.
The issue is , on different screen sizes , the lines are not appearing at the same place.
I tried multiplying the coordinates by the screen density dpi , but its still not working.
Snippet of my canvas code
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
bitmap = ((BitmapDrawable) zoom_lay.getBackground()).getBitmap();
mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
canvas = new Canvas(mutableBitmap);
canvas.drawColor(Color.TRANSPARENT);
zoom_lay.setBackground(new BitmapDrawable(getResources(), mutableBitmap));
final Path pathPolygon_2 = new Path();
pathPolygon_2.reset(); // only needed when reusing this path for a new build
canvas.drawLine(500,500,600,615,paint);
Thank you
Create your layout with the following params:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mainView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#mipmap/background"
tools:context=".MainActivity">
Can be any type, FrameLayout is just an example. The important part is to set it's width and height to match parent.
From there you can use your code to get the bitmap and draw on it only thing, let's say you want to draw the line horizontally in the center:
canvas.drawLine(0,muteableBitmap.getHeight()/2,muteableBitmap.getWidth(),muteableBitmap.getHeight()/2,paint);
And say you want a line vertically from the center:
canvas.drawLine(muteable.getWidth()/2,0,muteableBitmap.getWidth()/2,muteableBitmap.getHeight,paint);
I've written this manually so it might not compile due to capital letters and such, but it should work
first you need to get the size of the Bitmap, and then calculate the end points of the line according to your needs. For example, if you want to draw a line in the middle of the Bitmap, the Y coordinate is this Bitmap.getHeight() * 0.5f. I hope I can help you.
Bitmap mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
int height = mutableBitmap.getHeight();
int width = mutableBitmap.getWidth();
float startX = width * 0f;
float startY = height * 0.5f;
float stopX = width * 1f;
float stopY = height * 0.5f;
canvas.drawLine(startX, startY, stopX, stopY, paint);
I'm showing images from gallery to Imageview.
I'm using below code
Bitmap background = Bitmap.createBitmap((int) width, (int) height, Bitmap.Config.ARGB_8888);
float originalWidth = bMap.getWidth(), originalHeight = bMap.getHeight();
Canvas canvas = new Canvas(background);
float scale = width/originalWidth;
float xTranslation = 0.0f, yTranslation = (height - originalHeight * scale)/2.0f;
Matrix transformation = new Matrix();
transformation.postTranslate(xTranslation, yTranslation);
transformation.preScale(scale, scale);
Paint paint = new Paint();
paint.setFilterBitmap(true);
canvas.drawBitmap(bMap, transformation, paint);
imageView1.setImageBitmap(background);
Case 1: working.
Original Image
Output of above code.
Case 2: not working
Original Image.
Output of above code.
in case 2 why image is not getting scaled properly, to fill the imageview?
Please let me know where I'm going wrong.
Android already provides a method to create scaled bitmap. check this out LINK
Are you wanting it to stretch? Use fitxy.
Use the scaleType attribute on your ImageView in your layout xml file.
Example:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop" />
Then you can set your image on the ImageView using setImageUri(Uri uri) (I assume you have the Uri of the image to show).
I'm using the HorizontalScrollView and I want to put images inside it but images will be larger than the screen and makes users scroll horizontally while I'm using setScaleType(ImageView.ScaleType.CENTER_CROP) or other attributes.
How can I have images completely fit the screen? I prefer to use XML attributes if it is possible.
activity_main.xml
<HorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:id="#+id/main"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
</LinearLayout>
MainActivity.java
ImageView image = new ImageView(this);
image.setImageResource(getResources().getIdentifier('file_name', "drawable", getPackageName()));
image.setAdjustViewBounds(true);
image.setScaleType(ImageView.ScaleType.CENTER_CROP);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
image.setLayoutParams(layoutParams);
parent.addView(image);
You can use this xml property into your ImageView,
android:scaleType="fitXY"
Or use this dynamic code snippet to fit the ImageView accordingly the screen ratio,
private void scaleImage(ImageView view, int boundBoxInDp)
{
// Get the ImageView and its bitmap
Drawable drawing = view.getDrawable();
Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();
// Get current dimensions
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) boundBoxInDp) / width;
float yScale = ((float) boundBoxInDp) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
// Create a matrix for the scaling and add the scaling data
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// Create a new bitmap and convert it to a format understood by the ImageView
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
BitmapDrawable result = new BitmapDrawable(scaledBitmap);
width = scaledBitmap.getWidth();
height = scaledBitmap.getHeight();
// Apply the scaled bitmap
view.setImageDrawable(result);
// Now change ImageView's dimensions to match the scaled image
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
private int dpToPx(int dp)
{
float density = getApplicationContext().getResources().getDisplayMetrics().density;
return Math.round((float)dp * density);
}
And sample code for testing:
ImageView image = new ImageView(this);
scaleImage(image , 250); // in dp
Here's the output,
Before,
After,
Source: Scale image into ImageView, then resize ImageView to match the image
I am developing an application in which I need to fit an Bitmap into Imageview with specific dimensions(let's suppose 350dpx50dp - height*width).
I wanted to do something similar like this: http://gyazo.com/d739d03684e46411feb58d66acea1002
I have looked here for solutions. I found this code for scale the bitmap and fit it into imageview, but the problem is that imageview becomes greater when I add the bitmap into him:
private void scaleImage(Bitmap bitmap, ImageView view)
{
// Get current dimensions AND the desired bounding box
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int bounding = dpToPx(350);
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) bounding) / width;
float yScale = ((float) bounding) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
// Create a matrix for the scaling and add the scaling data
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// Create a new bitmap and convert it to a format understood by the ImageView
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
// Apply the scaled bitmap
view.setImageBitmap(scaledBitmap);
}
Using this code I can get this : http://gyazo.com/e9871db2130ac33668156fc0cf773594
But that's not what I wanted, I want to keep the dimensions of imageview and add the bitmap into imageview without modifying the dimensions of imageview and occupying all the imageview's surface. Like the first image.
Why don't you just add android:scaleType="fitXY" to your ImageView in xml?
Simple question where the simple answer isn't working. I have a bitmap and I want to get its dimensions as scaled to the display by the system for different DPI screens within the onDraw() method. bitmap.width() returns its unscaled width successfully. However, bitmap.getScaledWidth() returns zero. I have tried getScaledWidth(canvas) and getScaledWidth(canvas.getDensity()), but both return 0. Indeed, canvas.getDensity() returns zero so I can't even calculate it manually.
What am I doing wrong?
Bit more detail. I'm using a custom view. The bitmap is declared in the class and loaded in the constructor.
Edit:
I've found that using:
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
bitmap.getScaledHeight(metrics) returns the same value as bitmap.getHeight().
It would appear that bitmap.getWidth() returns the dimension of the resident bitmap after it has been scaled, meaning there's no apparent way to get the bitmap's original width.
The Canvas class has a lots of overloads for the drawBitmap() function. One of them allows you to scale/cut a Bitmap through a pretty comfortable interface.
public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
Where
Bitmap bitmap - is your bitmap you want to draw
Rect src - the source rect from your bitmap. If its not null, it will
cut out a piece from your bitmap (in the size and position of src)
RectF dst - This Rect will represent the Rectangle, your Bitmap will
fit in.
Paint paint - optional paint
And now an example! Lets say, you want to shrink your Bitmaps width to 1/2 and increase its height to 2 times of the original:
float startX = 0; //the left
float startY = 0; //and top corner (place it wherever you want)
float endX = startX + bitmap.getWidth() * 0.5f; //right
float endY = startY + bitmap.getHeight() * 2.0f; //and bottom corner
canvas.drawBitmap(bitmap, null, new RectF(startX, startY, endX, endY), null);
UPDATE
I don't really understand, what you are trying to acomplish, after reading your comment, but here is some extra info to get started:
Get the original size of a Bitmap without loading it into the memory:
BitmapFactory.Options options = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true; // bitmap wont be loaded into the memory
//won't load the Bitmap, but the options will contain the required information.
BitmapFactory.decodeStream(inputStream, null, options);
/*or*/ BitmapFactory.decodeFile(pathName, options);
int originalWidth = bitmapOptions.outWidth;
int originalHeight = bitmapOptions.outHeight;
Now if you have another your actual (scaled) Bitmap, or an ImageView, what you want to compare to the original, then you can use this (to get the width and height use getWidth() and getHeight()):
/*Get these values*/
int originalWidth, originalHeight, scaledWidth, scaledHeight;
float scaleWidthRatio = (float)scaledWidth / originalWidth;
float scaleHeightRatio = (float)scaledHeight / originalHeight;
How about this? You scale the bitmap yourself. :-)
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
Drawable drawable = getDrawable();
if(drawable==null)
Log.d("onDraw()","getDrawable returns null");
Bitmap fullSizeBitmap,scaledBitmap = null,roundBitmap = null;
fullSizeBitmap = ((BitmapDrawable)drawable).getBitmap() ;
//get width & height of ImageView
int scaledWidth = getMeasuredWidth();
int scaledHeight = getMeasuredHeight();
//bitmap, which will receive the reference to a bitmap scaled to the bounds of the ImageView.
if(fullSizeBitmap!=null)
scaledBitmap= getScaledBitmap(fullSizeBitmap,scaledWidth,scaledHeight);
//Now, draw the bitmap on the canvas
if(roundBitmap!=null)
canvas.drawBitmap(roundBitmap, 0,0 , null);
}