Edges of the bitmap got distorted when saving - android

I have a blank image and on that i put some stickers then i want to save the images. But when i save the image i find that its edges got distorted.
EDIT : there is also a problem. may be a trade off with edge distortion with sticker position.. it is chaning the position of the sticker. when i use 4000*2250 black image as background image and when i use 2000*1500 as background image it doesn't create any problem with the position but chg the resoulation of the image.
this is the pic before saving inside the app :
this is the pic after saving in my sd card:
Here is my bitmap saving code:
public Bitmap saveCurrentBitmap() {
EditActivity act = (EditActivity) mContext;
Bitmap origRawImage = act.getRawBitmap();
// copy to mutable
Bitmap rawImage = origRawImage.copy(Bitmap.Config.ARGB_8888, true);
if (rawImage == null)
return null;
Canvas canvas = new Canvas(rawImage);
// get scale factor
RectF scaledImg = act.getImageView().getInnerBitmapSize();
float scale = rawImage.getWidth() / scaledImg.width();
List<DraggableBitmap> stampList = act.getImageView().getOverlayList();
if (stampList.size() > 0) {
Enumeration<DraggableBitmap> e = Collections.enumeration(stampList);
while (e.hasMoreElements()) {
DraggableBitmap dBmp = (DraggableBitmap) e.nextElement();
Matrix finalMtx = new Matrix();
// calculate margin and move back
Matrix marginMtx = dBmp.getMarginMatrix();
float[] moveArr = new float[9];
marginMtx.getValues(moveArr);
float x = -(moveArr[0]);
float y = -(moveArr[3]);
Matrix moveBackMtx = new Matrix();
moveBackMtx.postTranslate(x, y);
// current manipulate matrix (rotate, zoom, move..)
Matrix manipulateMtx = dBmp.getCurrentMatrix();
Matrix scaleMtx = new Matrix();
// scale to original size
scaleMtx.postScale(scale, scale, 0, 0);
manipulateMtx = (manipulateMtx == null) ? new Matrix() : manipulateMtx;
finalMtx.postConcat(manipulateMtx);
finalMtx.postConcat(moveBackMtx);
finalMtx.postConcat(scaleMtx);
canvas.drawBitmap(dBmp.mBitmap, finalMtx, null);
}
}
return rawImage;
}
and this is the code that calling the savebitmap
private void saveImage() {
Bitmap bmpToSave = mActivityHelper.saveCurrentBitmap();
this.getBaseApplication().setRawBitmap(bmpToSave);
savedImagePath = SaveToStorageUtil.save(bmpToSave, this);
ImageScannerAdapter adapter = new ImageScannerAdapter(this);
adapter.scanImage(savedImagePath);
}

Try this:
Paint p = new Paint();
p.setAntiAlias(true);
canvas.drawBitmap(dBmp.mBitmap, finalMtx, p);

Related

Rotate around alternate axis

I am struggling with bitmap rotations. I wish to rotate a graphic around an alternate axis but I can only ever get it to rotate around the center point no matter what I do, putting in postTranlate. preTranslate, set Translate in any order doesnt work I have also tried the postRotate(45,0,0) but it always rotates around the center.
Code below taken of internet what would I do to alter its rotation point, the code below uses the launcher icon which is square I am using a long thin graphic like an arrow.
// Rotate image to 45 degrees.
public void RotateImage(){
ImageView image;
Bitmap bMap;
Matrix matrix;
//Get ImageView from layout xml file
image = (ImageView) findViewById(R.id.imageView1);
//Decode Image using Bitmap factory.
bMap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
//Create object of new Matrix.
matrix = new Matrix();
//set image rotation value to 45 degrees in matrix.
matrix.postRotate(45);
//Create bitmap with new values.
Bitmap bMapRotate = Bitmap.createBitmap(bMap, 0, 0,
bMap.getWidth(), bMap.getHeight(), matrix, true);
//put rotated image in ImageView.
image.setImageBitmap(bMapRotate);
}
I have tried the code below but its still rotates around the center or at least appears too
public void RotateImage{
ImageView image;
Bitmap bMap;
Matrix matrix;
//Get ImageView from layout xml file
image = (ImageView) findViewById(R.id.imageView);
//Decode Image using Bitmap factory.
bMap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
//Create object of new Matrix.
matrix = new Matrix();
//set image rotation value to 45 degrees in matrix.
matrix.setTranslate(-100,-200);
matrix.postRotate(angle);
matrix.postTranslate(100,200);
//Create bitmap with new values.
Bitmap bMapRotate = Bitmap.createBitmap(bMap, 0, 0,
bMap.getWidth(), bMap.getHeight(), matrix, true);
//put rotated image in ImageView.
image.setImageBitmap(bMapRotate);
Thanks
If you want your Bitmap to rotate 45 degree around x axis with pivot (a,b), you can call matrix.rotate(45, a, b)
Perhaps you want to use the Camera class to rotate around X, Y or Z axis:
matrix = new Matrix();
Camera camera = new Camera();
camera.save();
camera.rotateX(45f);
camera.getMatrix(matrix);
camera.restore();
The way I understand your question is that you want to rotate the image around some point, say (x, y). Conceptually you need to perform the following transformations on the image:
Translate by (-x, -y)
Rotate by 45 degrees
Translate by (x, y)
You can use this method to rotate an object from center create this method in sprite class
public void paintFromCenter(float angle, Canvas c) {
Bitmap b = sprite;
Bitmap h = b;
// Canvas canvas = new Canvas(a);
Matrix matrix = new Matrix();
matrix.postRotate(angle, h.getWidth() / 2, h.getHeight());
matrix.postTranslate(getX(), getY());
// canvas.drawBitmap(bitmap, matrix, new Paint());
Bitmap bmp2 = Bitmap.createBitmap(h, 0, 0, frameWidth, frameHeight,
matrix, true);
c.drawBitmap(h, matrix, null);
// g.getCanvas().drawBitmap(bmp2, getX(), getY(), null);
}
Now in onTouchEvent()
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
evX = (int) event.getX();
evY = (int) event.getY();
int initX = objectSprite.getX();
int inity = objectSprite.getY();
if ((evX > objectSprite.getX()
&& evX < objectSprite.getX() + objectSprite.getWidth()
&& evY > objectSprite.getY() && evY < objectSprite.getY()
+ objectSprite.getHeight())) {
if (angle < 90) {
angle += 5;
} else if (angle < -180)
angle -= 5;
}
}
return true;
}
in draw() method paint the image/object
private void draw(Canvas canvas) {
objectSprite.paintFromCenter(angle, canvas);
}
try it

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);

In Android, why is my combined bitmap blank?

I'm working with a set of layered images (think stacked) and I need to combine them into one element.
I'm basing my solution off Combine multiple bitmap into one
//send a map to the method that has my stored image locations in order
private Bitmap combineImageIntoOne(NavigableMap<Integer, String> layerImages) {
//size of my bitmaps
int w = 400, h = 400;
//bitmap placeholder
Bitmap productIndex = null;
//flattened layers
Bitmap temp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
//canvas to write layers to
Canvas canvas = new Canvas(temp);
int top = 0;
for (Map.Entry<Integer, String> e : layerImages.entrySet()) {
//create the layer bitmap
productIndex = decodeSampledBitmapFromResource(getResources(), e.getValue(), 400, 400);
//add layer to canvas
canvas.drawBitmap(productIndex, 0f, top, null);
}
//convert temp to a BitmapDrawable
Drawable d = new BitmapDrawable(getResources(),temp);
//set my image view to have the flattened image
carBase.setImageDrawable(d);
return temp;
}
The decodeSampledBitmapFromResource come from the Android docs about loading large bitmaps: Loading Large Bitmaps Efficiently You can review the code on that doc to see what I"m doing. I didn't edit the Android code much.
I've been using the Android code just fine to add layers to the FrameLayout but ended up running out of memory when the layers starting getting pretty high in number. This combining method is being used to conserve memory space.
Any ideas why the final bitmap doesn't have any content?
Reference LINK <-------------------------
public Bitmap combineImages(Bitmap c, Bitmap s) { // can add a 3rd parameter 'String loc' if you want to save the new image - left some code to do that at the bottom
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, c.getWidth(), 0f, null);
// this is an extra bit I added, just incase you want to save the new image somewhere and then return the location
/*String tmpImg = String.valueOf(System.currentTimeMillis()) + ".png";
OutputStream os = null;
try {
os = new FileOutputStream(loc + tmpImg);
cs.compress(CompressFormat.PNG, 100, os);
} catch(IOException e) {
Log.e("combineImages", "problem combining images", e);
}*/
return cs;
}

Translating using Matrix Android

I am trying to translate a image using matrix my code is
Bitmap myImg = BitmapFactory.decodeResource(getResources(), R.drawable.calednder_c);
Matrix matrix = new Matrix();
matrix.setTranslate(500,300 );
Bitmap rotated = Bitmap.createBitmap(myImg, 0, 0, myImg.getWidth(), myImg.getHeight(),
matrix, true);
circle.setImageBitmap(rotated);
when i am calling my animate method nothing happening .while i wrote preRotate(angle); it rotate and it scale also but not translate why what i am missing
Thanks in advance
Here is the respective snippet from the createBitmap source code:
final boolean transformed = !m.rectStaysRect();
RectF deviceR = new RectF();
m.mapRect(deviceR, dstR);
neww = Math.round(deviceR.width());
newh = Math.round(deviceR.height());
bitmap = createBitmap(neww, newh, transformed ? Config.ARGB_8888 : newConfig,
transformed || source.hasAlpha());
canvas.translate(-deviceR.left, -deviceR.top);
canvas.concat(m);
paint = new Paint();
paint.setFilterBitmap(filter);
if (transformed) {
paint.setAntiAlias(true);
}
It makes the created bitmap just big enough to hold all the desired pixels from the original bitmap. This is caused by the new size and the canvas.translate call.
The net effect is that translations in the matrix are ignored.

How can I make image opaque to some level?

I would like to know if I can make an image opaque if set in image view or set as background of relative layout.
How can I make image opaque using image view or relative layout for setting the image dynamically or Is there any other option to set image and its opacity dynamically?
I also want the same image to rotate in both directions and also can zoomin and zoomout to anylevel.
Thanks in advance
Working and tested code below.
private void applyTransformToImageView(int code)
{
Bitmap bmpOriginal = BitmapFactory.decodeResource(this.getResources(), R.drawable.image2);
Bitmap bmResult = Bitmap.createBitmap(bmpOriginal.getWidth(), bmpOriginal.getHeight(), Bitmap.Config.ARGB_8888);
Canvas tempCanvas = new Canvas(bmResult);
switch (code)
{
case CHANGE_TRANSPARENCY:
{
Paint alphaPaint = new Paint();
alphaPaint.setAlpha(128);
tempCanvas.drawBitmap(bmpOriginal, 0, 0, alphaPaint);
}
break;
case ROTATE:
{
tempCanvas.rotate(90, bmpOriginal.getWidth()/2, bmpOriginal.getHeight()/2);
tempCanvas.drawBitmap(bmpOriginal, 0, 0, null);
}
break;
case ZOOM_IN:
{
Rect zoomRegion = new Rect();
zoomRegion.left = 0;
zoomRegion.top = 0;
zoomRegion.right = bmpOriginal.getWidth()/2;
zoomRegion.bottom = bmpOriginal.getHeight()/2;
Rect display = new Rect();
display.left = 0;
display.top = 0;
display.right = bmpOriginal.getWidth();
display.bottom = bmpOriginal.getHeight();
tempCanvas.drawBitmap(bmpOriginal, zoomRegion, display, null);
}
break;
default:
}
mImageView.setImageBitmap(bmResult);
}
sets alpha to semi-transparent - value 128
rotates around original image center for 90 degrees
zoom into top left quadrant of the original image

Categories

Resources