Scale factor in painting app is wrong - android

My goal is to move my finger over the screen to paint on a picture in an imageview mImageView. The picture there is resized to imageview-size to improve performance. Later I want to export this to the big image again, this is where scaleFactor comes in. When multiplying the real device coordinates with this factor, I should get where paint on the real images goes.
path is the uri to the underlying picture.
But it's always off, the areas I want to paint are not being painted in the final image. In general, scaleFactor is too big. Where is the problem? Or is this code right and the problem likely elsewhere?
scaleFactor is defined here for the first time.
private void displayFunction(Uri path) {
iv = (ImageView)findViewById(R.id.mImageView);
int ivWidth = iv.getWidth();
int ivHeight = iv.getHeight();
Bitmap v = null;
try {
v = MediaStore.Images.Media.getBitmap(this.getContentResolver(), path);
}
catch (Exception vc)
{
return;
}
if (v == null) return;
int originalWidth = v.getWidth();
int originalHeight = v.getHeight();
float rs = (float)originalWidth / (float)originalHeight;
Bitmap bitmap2 = null;
if (rs > 1)
bitmap2 = getResizedBitmap(v,(int)((float)ivWidth / rs),ivWidth);
else
bitmap2 = getResizedBitmap(v,ivHeight,(int)((float)ivHeight * rs));
scaleFactor = Math.max((float)originalWidth/(float)ivWidth, (float)originalHeight/(float)ivHeight);
v = null;
bmpTemp = clearPainting(bitmap2, Color.RED, 1, Paint.Style.STROKE);
iv.post(new Runnable() {
public void run() {
iv.setScaleType(ImageView.ScaleType.FIT_XY);
iv.setImageBitmap(bmpTemp);
}
});
}
and
<android.support.design.widget.CoordinatorLayout
android:id="#+id/myCoordinatorLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="de.noahsofie.bildzuschneiden.MainActivity">
<ImageView
android:id="#+id/mImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:contentDescription="#string/html"
android:scaleType="centerCrop" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>

You want to display the big image only or paint on it as well? If the goal is to display the large bitmap only, you can draw the paths on the bitmap using canvas, and then scale the bitmap to any size that you want.

Related

Save Imageview With textview to bitmap

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.

Activity runs slow with a couple of ImageView-s

I have an activity containing 4 images in total. They are all matching the resolution of a 1080x1920 device. When I run the activity with those images, which are loaded directly in my activity via the XML, it runs tremendously slow in my Genymotion emulator and lags on a real Android device.
Here is the setup:
<android.support.design.widget.AppBarLayout
...>
<android.support.design.widget.CollapsingToolbarLayout
...>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="vertical"
app:layout_collapseMode="parallax">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/imageView"
android:src="#drawable/shot_header"
android:scaleType="centerCrop" />
</LinearLayout>
<android.support.v7.widget.Toolbar
.../>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
The first image is in a CollapsingToolbarlayout. The resolution of the image is 1080x649 PNG.
The content_activity:
This image fills the parent width.It's resolution is 1080x772 PNG.
<ImageView
android:layout_width="match_parent"
android:layout_height="250dp"
android:id="#+id/main_image"
android:layout_below="#+id/shot_error_field"
android:src="#drawable/forehand_midpng"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:layout_marginTop="15dp"/>
The other 2 images are in a LinearLayout, their resolution is 500x399
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/main_image">
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:id="#+id/imageView3"
android:src="#drawable/forehand_mid_wrong"
android:layout_weight="1"/>
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" >
</View>
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:id="#+id/imageView4"
android:src="#drawable/forehand_mid_wrong"
android:layout_weight="1"/>
</LinearLayout>
To summarize, I have an activity with 4 ImageViews, populated with properly sized images, which should no problem for a modern Android device. The problem is that this activity is running extremely slow and lagging due to a high memory consumption.
Am I doing something wrong? How can I further optimize those images?
I looked into other threads- out of memory issue but none seems to propose a solution to such a problem.
Problem is resolution of the image, if you can reduce resolution of the image then work fine, here is some example for reducing image resolution and size.
If you pass bitmap width and height then use below function.
public Bitmap getResizedBitmap(Bitmap image, int bitmapWidth,
int bitmapHeight) {
return Bitmap.createScaledBitmap(image, bitmapWidth, bitmapHeight,
true);
}
if you want bitmap ratio same and reduce bitmap size. then pass your maximum size bitmap. you can use this function
public Bitmap getResizedBitmap(Bitmap image, int maxSize) {
int width = image.getWidth();
int height = image.getHeight();
float bitmapRatio = (float)width / (float) height;
if (bitmapRatio > 0) {
width = maxSize;
height = (int) (width / bitmapRatio);
} else {
height = maxSize;
width = (int) (height * bitmapRatio);
}
return Bitmap.createScaledBitmap(image, width, height, true);
}
or if you are using drawable resources then use this method
public Drawable resizeImage(int imageResource) {// R.drawable.large_image
// Get device dimensions
Display display = getWindowManager().getDefaultDisplay();
double deviceWidth = display.getWidth();
BitmapDrawable bd = (BitmapDrawable) this.getResources().getDrawable(
imageResource);
double imageHeight = bd.getBitmap().getHeight();
double imageWidth = bd.getBitmap().getWidth();
double ratio = deviceWidth / imageWidth;
int newImageHeight = (int) (imageHeight * ratio);
Bitmap bMap = BitmapFactory.decodeResource(getResources(), imageResource);
Drawable drawable = new BitmapDrawable(this.getResources(),
getResizedBitmap(bMap, newImageHeight, (int) deviceWidth));
return drawable;
}
/************************ Resize Bitmap *********************************/
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height,
matrix, false);
return resizedBitmap;
}
Actually this should not be an issue and these images are not so big to make you phone laggy. Take a look on other stuff you have in the application, it is possible there is some heavy operations (like DB writing/readin, API requests) right in UI thread.
If there is no such operations and you see such problems with the perfomance, try to set these images via some libraries, like Picasso.
Gradle dependency:
compile 'com.squareup.picasso:picasso:2.4.0'
And code will look like this:
Picasso.with(this).load(R.drawable.my_image).into(toolbar);
TRY
Definitely reduce the size of the images.
Cache images if you can.
Download the images on a different thread. Store a HashMap would
make it easy for you
When you get the list of image urls, iterate through them:
pictures.put(id,view);
try{
FileInputStream in = openFileInput(id);
Bitmap bitmap = null;
bitmap = BitmapFactory.decodeStream(in, null, null);
view.setImageBitmap(bitmap);
}catch(Exception e){
new Thread(new PictureGetter(this,mHandler,id)).start();
}
Code to update the image view:
if(id!=null){
ImageView iv = pictures.get(id);
if(iv!=null){
try{
FileInputStream in = openFileInput(id);
Bitmap bitmap = null;
bitmap = BitmapFactory.decodeStream(in, null, null);
iv.setImageBitmap(bitmap);
}catch(Exception e){
}
}
Try facebook's fresco library. It can handle large images and one of my projects, reduces memory consumption about 50%.

mapping preview image coordinates to final image coordinates

I am using the CommonsWare CWAC-Camera library (https://github.com/commonsguy/cwac-camera) to wrap the native Android Camera API.
I would like to allow the user to select a point on the preview image before taking a picture, then (accurately) pick out that same point on the final image after they have taken the picture. While this works approximately, the markup on the final image is typically off-target by about 100-200 pixels.
To start with, I am capturing the user's original selected point by setting an OnTouchListener on the CameraView. I am then storing the X and Y coordinates from the MotionEvent. Just to help with visual verification, I am also immediately drawing a circle at the coordinates the user selected, before they take the picture.
When the user takes the picture, I have subclassed from SimpleCameraHost to override saveImage, in order to draw a corresponding circle on the final image before it is written to storage. In order to calculate where to draw the circle on the final image, I am doing the following:
Create a Bitmap the same size and shape as the TextureView that was used to draw the preview
Draw a circle on that Bitmap at the same coordinates as was drawn on-screen
Scale the markup-Bitmap up to the final image size (using Matrix.ScaleToFit.Center) and overlay it on top of the actual final photo image
This is not sufficiently accurate, however - at least, not on the Nexus 7 (2013) that I am testing with. I am not sure what I am missing in the placement calculations for adding the markup to the final image.
A simplified example to demonstrate the problem follows:
MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCameraContainer = findViewById(R.id.camera_container);
mCanvasView = (CanvasView)findViewById(R.id.canvas_view);
FragmentManager fmgr = getFragmentManager();
FragmentTransaction ft = fmgr.beginTransaction();
mCameraFragment = (CameraFragment)fmgr.findFragmentByTag(CAMERA_FRAGMENT_TAG);
if (null == mCameraFragment) {
mCameraFragment = new CameraFragment();
ft.add(R.id.camera_container, mCameraFragment, CAMERA_FRAGMENT_TAG);
}
ft.commit();
if (null == mCameraHost) {
mCameraHost = new MyCameraHost(this);
}
mCameraFragment.setHost(mCameraHost);
ViewTreeObserver ccObserver = mCameraContainer.getViewTreeObserver();
ccObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
CameraView cv = (CameraView)mCameraFragment.getView();
View previewWidget = ((ViewGroup)cv).getChildAt(0);
mCameraHost.setPreviewSize(previewWidget.getWidth(), previewWidget.getHeight());
cv.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent e) {
mCanvasView.setPoint(e.getX(), e.getY());
mCameraHost.setPoint(e.getX(), e.getY());
return true;
}
});
mCameraContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
Button photoButton = (Button)findViewById(R.id.takePhotoButton);
photoButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mCameraFragment.takePicture();
}
});
}
MyCameraHost.java:
#Override
public void saveImage(PictureTransaction xact, byte[] image) {
// decode the final image as a Bitmap
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap imageBitmap = BitmapFactory.decodeByteArray(image, 0, image.length, opt);
// draw a blank Bitmap with just the markup, using a canvas size equivalent to the preview view
Bitmap markerBitmap = Bitmap.createBitmap(previewViewWidth, previewViewHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(markerBitmap);
Paint p = new Paint();
p.setStrokeWidth(10);
p.setStyle(Style.FILL);
p.setColor(Color.BLUE);
c.drawCircle(previewMarkerX, previewMarkerY, 20, p);
// scale the markup bitmap up to final-image size using Matrix.ScaleToFit.CENTER
Matrix m = new Matrix();
m.setRectToRect(new RectF(0, 0, previewViewWidth, previewViewHeight), new RectF(0, 0, imageBitmap.getWidth(), imageBitmap.getHeight()), Matrix.ScaleToFit.CENTER);
// overlay the scaled marker Bitmap onto the image
Canvas imageCanvas = new Canvas(imageBitmap);
imageCanvas.drawBitmap(markerBitmap, m, null);
// save the combined image
ByteArrayOutputStream bos = new ByteArrayOutputStream();
imageBitmap.compress(CompressFormat.JPEG, 70, bos);
byte[] image2 = bos.toByteArray();
super.saveImage(xact, image2);
}
layout XML:
<RelativeLayout 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" >
<FrameLayout
android:id="#+id/camera_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.example.cwaccameratouchpoint.CanvasView
android:id="#+id/canvas_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#id/camera_container"
android:layout_alignRight="#id/camera_container"
android:layout_alignTop="#id/camera_container"
android:layout_alignBottom="#id/camera_container" />
<Button
android:id="#+id/takePhotoButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:text="go" />
</RelativeLayout>
As per comments from CommonsWare, I updated saveImage below to include the full-bleed offset and to spell out the transform calculations. It is an improvement, but still not as accurate as it should be:
// decode the final image as a Bitmap
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap imageBitmap = BitmapFactory.decodeByteArray(image, 0, image.length, opt);
int finalImageWidth = imageBitmap.getWidth();
int finalImageHeight = imageBitmap.getHeight();
// calculate selected point x and y values as applied to full-size final image
// apply full-bleed-based offset, where xoffset and yoffset represent the
// offset of the TextureView within its parent CameraView
int bleedAdjustedX = (int)previewMarkerX - xoffset;
int bleedAdjustedY = (int)previewMarkerY - yoffset;
// calculate offset for change in aspect ratio
// for now, assume portrait orientation only
double finalImageAspectRatio = (double)finalImageHeight / (double)finalImageWidth;
double aspectAdjustedWidth = (double)previewViewHeight / finalImageAspectRatio;
double aspectXOffset = (aspectAdjustedWidth - previewViewWidth) / 2;
int aspectAdjustedX = bleedAdjustedX + (int)aspectXOffset;
// scale adjusted coordinates for full-size image
double normalizedAdjustedX = (double)aspectAdjustedX / aspectAdjustedWidth;
double normalizedAdjustedY = (double)bleedAdjustedY / (double)previewViewHeight;
double scaledX = normalizedAdjustedX * (double)finalImageWidth;
double scaledY = normalizedAdjustedY * (double)finalImageHeight;
// draw markup on final image
Canvas c = new Canvas(imageBitmap);
Paint p = new Paint();
p.setStrokeWidth(10);
p.setStyle(Style.FILL);
p.setColor(Color.BLUE);
c.drawCircle((float)scaledX, (float)scaledY, 20, p);
// save marked-up image
ByteArrayOutputStream bos = new ByteArrayOutputStream();
imageBitmap.compress(CompressFormat.JPEG, 70, bos);
byte[] image2 = bos.toByteArray();
super.saveImage(xact, image2);

android placing bitmap in middle

I am designing a drawing app where user can import image from gallery and then scale up or down to fit the screen width or height. so that user can draw onto the imported picture, using the below code.
I am extending View, named DrawView. The DrawView is same as screenwidth, but its height is less than screenheight because there are some buttons above it, placing the DrawView to the bottom of the Screen under the functioning buttons, and so I declared DrawViewHeight.
See below for examples for dimension and results of variables.
Question:
The bitmap can be properly loaded and scaled to fit to the DrawView.
However, it is located at the top of the DrawView. I would like to place it in the middle of the screen, so i added the following code but still FAILS.
bitmapCanvas.drawBitmap(bitmap, x_adjustment, y_adjustment, null);
How could it be further modified such that the imported image (decoded and copied as bitmap while importing) is placed center of DrawView, with blank space (eg. white) above and below and left and right of the loaded scaled bitmap image?
Note: Those surrounding space around the image are not to be drawn onto by user.
Codes:
Declarations:
private Bitmap bitmap; // drawing area for display or saving
private Canvas bitmapCanvas; // used to draw on bitmap
OnSizeChanged:
public void onSizeChanged(int w, int h, int oldW, int oldH)
{
super.onSizeChanged(w, h, oldW, oldH);
DrawViewWidth = w;
DrawViewHeight = h;
bitmap = Bitmap.createBitmap(getWidth(), DrawViewHeight, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmap);
bitmap.eraseColor(Color.WHITE); // erase the BitMap with white
}
OnDraw:
#Override
protected void onDraw(Canvas canvas) // called each time this View is drawn
{
canvas.drawBitmap(bitmap, 0, 0, paintScreen);
}
Load Pictures:
public void load_pic(final String picturePath)
{
// get screen dimension first
WindowManager wm = (WindowManager) context_new.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
final int screenWidth = display.getWidth();
final int screenHeight = display.getHeight();
//get importing bitmap dimension
Options op = new Options();
op.inJustDecodeBounds = true;
Bitmap pic_to_be_imported = BitmapFactory.decodeFile(picturePath, op);
final int x_pic = op.outWidth;
final int y_pic = op.outHeight;
// scaling
final int IMAGE_MAX_SIZE= (int) Math.max(DrawViewWidth, DrawViewHeight);
int scale = 1;
if (op.outHeight > IMAGE_MAX_SIZE || op.outWidth > IMAGE_MAX_SIZE) {
scale = (int)Math.pow(2, (int) Math.round(Math.log(IMAGE_MAX_SIZE / (double) Math.max(op.outHeight, op.outWidth)) / Math.log(0.5))); }
final BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
// Start loading image to the DrawView
if ((x_pic > DrawViewWidth) || (y_pic > DrawViewHeight))
{
AlertDialog.Builder onBackBuilder = new AlertDialog.Builder(context_new);
onBackBuilder.setPositiveButton(R.string.buttontext_create_load_pic_stretch, new DialogInterface.OnClickListener()
{
//skipped
}
onBackBuilder.setNegativeButton(R.string.buttontext_create_load_pic_keep_scale, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id)
{
float xratio = (float) x_pic / (float) screenWidth;
float yratio = (float) y_pic / (float) DrawViewHeight;
int adjusted_x = 0;
int adjusted_y = 0;
if (xratio >= yratio) {adjusted_x = screenWidth; adjusted_y = (int) (y_pic / xratio);}
if (xratio < yratio) {adjusted_y = DrawViewHeight; adjusted_x = (int) (x_pic / yratio);}
bitmap = (BitmapFactory.decodeFile(picturePath, o2));
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
bitmap = Bitmap.createScaledBitmap(bitmap, adjusted_x, adjusted_y, true);
int x_adjustment = (screenWidth - adjusted_x) /2;
int y_adjustment = (DrawViewHeight -adjusted_y) /2;
bitmapCanvas.drawBitmap(bitmap, x_adjustment, y_adjustment, null);
// How to modify to put to center of DrawView????
invalidate();
}
});
AlertDialog alert = onBackBuilder.create();
alert.show();
}
Examples of dimension and results of variables:
Screen : 480W * 800H
DrawView : 480W * 590H
Original image : 3264W * 2448H
Scaled image : adjusted_x=480 (meet screenwidth), adjusted_y=360
x_adjustment : 0
y-adjustment : 115
Layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.pearmak.drawing.DrawView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center_vertical|center_horizontal|center"
android:background="#drawable/drawview_border" />
</RelativeLayout>
// You can try this :
int width = containerBitmap.getWidth();
int height = containerBitmap.getHeight();
float centerX = (width - centeredBitmap.getWidth()) * 0.5f;
float centerY = (height- centeredBitmap.getHeight()) * 0.5f;
mCanvas.drawBitmap(centeredBitmap, centerX, centerY, paint);
You can use it to draw a bitmap at the center of another bitmap.
In your onDraw() you specify (0,0) as the bitmap (x,y) which will draw it at the top left corner of your DrawView so your x_adjustment, y_adjustment effect is lost once onDraw is called.
You should do your bitmap location adjustment code inside onDraw not inside onClick
#Override
protected void onDraw(Canvas canvas) // called each time this View is drawn
{
canvas.drawBitmap(bitmap, x_adjustment, y_adjustment, null);
}
The LayoutParameters of your imageview or the imageview's parent view need to specify centering within the screen
also, post your XML layout if there is one, as well as where you make the bitmap part of an imageview in your code
As iTech has noted, to get your Bitmap drawn in the center of the DrawView, you need to draw it in the correct location inside your onDraw method.
Create two additional fields:
int x_adjust, y_adjust;
In your onClick (when loading the bitmap), calculate the correct center, and set x_adjust and y_adjust to the relevant values. Then make sure you use these values in the onDraw method (rather than 0,0).
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmap, x_adjust, y_adjust, null);
}
Note: Make sure to recalculate x_adjust and y_adjust in the onSizeChanged method also. Otherwise the bitmap will no longer be centered after you rotate the device.

Canvas scaling retains pixel size

I'm trying to do some image processing on the camera preview, but being too slow I under sample time image and do the processing on a smaller scale. Then I overlay the processed (thresholded) image over the preview. My problem is that when I scale the smaller image to fit the camera preview the pixels stay the same size... I would like to see some big pixels due to the scaling, but I can't.
Here's the XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
android:orientation="vertical" >
<SurfaceView
android:id="#+id/svPreview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<SurfaceView
android:id="#+id/svOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true" />
</RelativeLayout>
And the thread that gets the camera preview image bytes and does the thresholding:
class PathThread extends Thread implements PreviewCallback
{
private final int width, height;
private final SurfaceHolder holder;
private Canvas overlayCanvas;
private int samples = 8;
final private float scale;
final private Paint red, blue, yellow;
public PathThread(int canvasWidth, int canvasHeight, SurfaceView canvasView)
{
// This is how much smaller image I want
width = canvasWidth / samples;
height = canvasHeight / samples;
holder = canvasView.getHolder();
// Scale to fit the camera preview SurfaceView
scale = (float) canvasView.getWidth() / height;
// No smoothing when scaling please
yellow = new Paint();
yellow.setColor(Color.parseColor("#ffbb33"));
yellow.setAntiAlias(false);
yellow.setDither(false);
yellow.setFilterBitmap(false);
}
public void onPreviewFrame(byte[] data, Camera camera)
{
overlayCanvas = holder.lockCanvas();
overlayCanvas.drawColor(0, Mode.CLEAR);
overlayCanvas.scale(scale, scale);
// Do the image processing and make a [samples] times smaller image
// Boring, pseudo-optimized, per-pixel thresholding process
holder.unlockCanvasAndPost(overlayCanvas);
}
}
This is the result:
I'm aware that it's a little bit offset, but that's the least of my problems.
Solution:
After 2 more days of searching it was quite simple, but not very easy to find/understand:
With the holder of the SurfaceView where I draw I had to call this:
canvasHolder.setFixedSize(width, height);
I experimented with different values and found what I needed. This makes big pixels.

Categories

Resources