Low Quality after scaling Bitmap to lower resolution - android

I am trying to scale down a Bitmap but the edges are not clear as the original image, its little blurred
I have checked out the below link
Bad image quality after resizing/scaling bitmap
Please help
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,data.length);
Matrix m=new Matrix();
m.postRotate(90);
//m.postScale((float)0.5,(float) 0.5);
//Added for merging
//Bitmap mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Bitmap mutableBitmap = Bitmap.createBitmap(bitmap,0,0,600,400,m,false);
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
Canvas canvas = new Canvas(mutableBitmap);
View v=(View)relLay.getParent();
v.setDrawingCacheEnabled(true);
v.buildDrawingCache();
Options options = new BitmapFactory.Options();
options.inScaled = false;
//options.inJustDecodeBounds=true;
options.inSampleSize=2;
//Bitmap viewCapture = v.getDrawingCache().copy(Bitmap.Config.ARGB_8888, true);
// Bitmap newImage = Bitmap.createScaledBitmap(viewCapture, viewCapture.getWidth()/2, viewCapture.getHeight()/2, true);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
(v.getDrawingCache().copy(Bitmap.Config.ARGB_8888, true)).compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
Bitmap viewCapture= BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length, options);
v.setDrawingCacheEnabled(false);
Rect src = new Rect(0, 0, viewCapture.getWidth(), viewCapture.getHeight());
Log.d("TEST",""+viewCapture.getWidth()+" "+viewCapture.getHeight());
//Destination RectF sized to the camera picture
Rect dst = new Rect(0, 0, mutableBitmap.getWidth(), mutableBitmap.getHeight());
Log.d("Test",""+mutableBitmap.getWidth()+" "+mutableBitmap.getHeight());
canvas.drawBitmap(viewCapture, src, dst, paint);
// Bitmap newImage = Bitmap.createScaledBitmap(viewCapture, 400,600, true);
mutableBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
The viewCapture element gets blurred out if I try to scale

Let me try to help you.
First of all, If you your desired Camera Captured Picture size is 600*400 or similar size then
I would say set the camera param for your desired size (which is supported by camera) and you will get the small image in Camera's Picture taken method
Note : but make sure first you need to check what ate picture sizes supported by Device camera. then set one of them.
Here is the one example I tested for Galaxy Nexus
Galaxy Nexus Camera Supported Picture sizes
Supported Picture Size. Width: 2592 * height : 1944
Supported Picture Size. Width: 2592 * height : 1728
Supported Picture Size. Width: 2592 * height : 1458
Supported Picture Size. Width: 2048 * height : 1536
Supported Picture Size. Width: 1600 * height : 1200
Supported Picture Size. Width: 1280 * height : 1024
Supported Picture Size. Width: 1152 * height : 864
Supported Picture Size. Width: 1280 * height : 960
Supported Picture Size. Width: 640 * height : 480
Supported Picture Size. Width: 320 * height : 240
below is the sample code will help you
CameraActivity.java
public class CameraActivity extends Activity implements SurfaceHolder.Callback,
OnClickListener
{
Camera camera;
SurfaceHolder surfaceHolder;
boolean previewing = false;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getWindow().setFormat(PixelFormat.UNKNOWN);
surfaceView = (SurfaceView) findViewById(R.id.surfaceview);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
{
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder arg0)
{
// TODO Auto-generated method stub
Log.v(TAG, "surfaceCreated get called");
camera = Camera.open();
camera.setDisplayOrientation(90); //to get portrait display
if (camera != null) {
try {
//Here is the main logic
// We are setting camera parameters as our desired picture size
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPictureSizes();
Camera.Size result = null;
for (int i=0;i<sizes.size();i++)
{
result = (Size) sizes.get(i);
Log.i("PictureSize", "Supported Size. Width: " + result.width + "height : " + result.height);
if(result.width == 640)
{
parameters.setPreviewSize(result.width, result.height);//640*480
parameters.setPictureSize(result.width, result.height);
//Now if camera support for 640*480 pictures size you will get captured image as same size
}
else
{
//to do here
}
}
camera.setParameters(parameters);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
previewing = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
Log.v(TAG, "surfaceDestroyed get called");
camera.stopPreview();
camera.release();
camera = null;
previewing = false;
}
}
Let me know your comment in this.

Related

Android Camera.takePicture() saves pictures with 176x144 pixels

I have programmed an App with a CameraPreview. When I take a Photo now, the App save it with 176 x 144 Pixels. Can I Change the width an the height?
I use the Camera Api, not Camera2.
When I took photos with the normal Camera-App, it saved Images with 2368x4208 Pixels.
This is where the Photos where taken
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap rawImg = BitmapFactory.decodeByteArray(data, 0, data.length);
Log.e("TakePicture", "Picture Callback erreicht");
shotAnalyser.startAnalysation(rawImg, data);
}
Here I grab the Data and make a Bitmap
public void startAnalysation(final Bitmap rawImg, final byte[] data){
Bitmap rawBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
// Ermitteln der nötigen Bild-Eigenschaften
int width = rawBitmap.getWidth();
int height = rawBitmap.getHeight();
}
Here I tried to Change the PictureSize
public Camera getCameraInstance(){
Camera c = null;
try {
releaseCameraAndPreview();
c = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK); // attempt to get a Camera instance
Log.e(LOG, "CameraInstance: " + c + " RUNS");
Camera.Parameters parameters = c.getParameters();
parameters.set("jpeg-quality", 70);
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setPictureSize(2048, 1232);
c.setParameters(parameters);
}
catch (Exception e){
}
return c; // returns null if camera is unavailable
}
I've googled a lot, but I can't find anything.

android mediaprojection screenshot contains black frame

I am working on recording my screen with MediaProjection
as follows
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
displayWidth = size.x;
displayHeight = size.y;
imageReader = ImageReader.newInstance(displayWidth, displayHeight, ImageFormat.JPEG, 5);
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
DisplayMetrics metrics = getResources().getDisplayMetrics();
int density = metrics.densityDpi;
mediaProjection.createVirtualDisplay("test", displayWidth, displayHeight, density, flags,
imageReader.getSurface(), null, projectionHandler);
Image image = imageReader.acquireLatestImage();
byte[] data = getDataFromImage(image);
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
Problem is that captured images contains black frame like image below.
EDIT
The above issue can be solved with bitmap operations.
However, I am now looking for a solution that can be applied to MediaProjection or to SurfaceView of ImageReader to implement device recording.
I had a similar issue. The following code exhibits this problem.
final DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
final int width = metrics.widthPixels;
final int height = metrics.heightPixels;
final int densityDpi = metrics.densityDpi;
final int MAX_IMAGES = 10;
mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, MAX_IMAGES);
mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCaptureTest",
width, height, densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mImageReader.getSurface(), null, null);
Replacing this:
getWindowManager().getDefaultDisplay().getMetrics(metrics);
With this:
getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
Fixes it. The problem is that the decorations around the image corrupt the actual resolution of the screen. getMetrics() returns a height (or width in landscape) that is not accurte, and has the home, back, etc, buttons subtracted. The actual display area available for developers is (1440 x 2326... or something like that). But of course, the captured image is going to be the full 1440 X 2560 screen resolution.
If you do not have control over the image yourself, you can modify it by doing something like, assuming your Bitmap is called image.
Bitmap imageWithBG = Bitmap.createBitmap(image.getWidth(), image.getHeight(),image.getConfig()); // Create another image the same size
imageWithBG.eraseColor(Color.BLACK); // set its background to white, or whatever color you want
Canvas canvas = new Canvas(imageWithBG); // create a canvas to draw on the new image
canvas.drawBitmap(image, 0f, 0f, null); // draw old image on the background
image.recycle();
Based on your comments I think this is what you are looking for
Bitmap bitmap; //field
Bitmap croppedBitmap; // field
Image image;// field
Handler mHandler; //field
new Thread() {
#Override
public void run() {
Looper.prepare();
mHandler = new Handler();
Looper.loop();
}
}.start();
imageAvailableListener = new ImageReader.OnImageAvailableListener {
#Override
public void onImageAvailable(ImageReader reader) {
try {
image = reader.acquireLatestImage();
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
Rect rect = image.getCropRect();
croppedBitmap = Bitmap.createBitmap(bitmap,rect.left,rect.top,rect.width(),rect.height());
\\Do whatever here...
image.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bitmap!=null) {
bitmap.recycle();
}
if (croppedBitmap!=null) {
bitmap.recycle();
}
if (image!=null) {
image.close();
}
}
}
}
imageReader.setOnImageAvailableListener(imageAvailableListener, mHandler);

android scale bitmap to screen dimension [duplicate]

This question already has answers here:
Android scaling of images to screen density
(3 answers)
Closed 7 months ago.
actually I'm trying to create simple app with wallpapers.
I'm trying to scale my image to user device screen size.
I'm using code like bellow:
/*
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int width = metrics.widthPixels;
*/
Display metrics = getWindowManager().getDefaultDisplay();
int height = metrics.getHeight();
int width = metrics.getWidth();
float fourToThree;
int wymiar;
Bitmap mbitmap; //definicja zmiennej przechowującej bitmapę
try {
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), cardBase.cardImages[position]);
//UP - zapisanie obrazu z tablicy do zmiennej bitmapy
/*if(height>=width) {
fourToThree = height * 0.75f; //height
wymiar = (int)Math.round(fourToThree);
mbitmap = Bitmap.createScaledBitmap(myBitmap, height, wymiar, true);
} else {
fourToThree = height * 0.75f;
wymiar = (int)Math.round(fourToThree);
mbitmap = Bitmap.createScaledBitmap(myBitmap, width, wymiar, true);
}*/
mbitmap = Bitmap.createScaledBitmap(myBitmap, width, height, true);
myWallpaper.setBitmap(mbitmap);
Toast.makeText(SelectedCard.this, "Wallpaper changed", Toast.LENGTH_LONG).show();
}
catch (IOException e) {
e.printStackTrace();
Toast.makeText(SelectedCard.this, "Sorry, an error occurred", Toast.LENGTH_LONG).show();
}
I was trying many other ways but still have my image larger then device screen :(
I'm testing it on virtual phone and I was trying to create image dit 160 dpi as a device screen, it's not working too.
Can anyone tell me, how can I scale my image (jpg - 320 x 480 px, 300 dpi) to set it as a wallpaper on device ?
Any ideas ?
thanks :)
Ps. sorry for text mistakes, English is my second language ;p
Ok, i have something like that:
imgView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
WallpaperManager myWallpaper = WallpaperManager.getInstance(getApplicationContext());
try
/*{
myWallpaper.setResource(HdImageBase.HdImages[position]);
Toast.makeText(ImageMini.this, "Wallpaper changed", Toast.LENGTH_LONG).show();
}*/
{
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int width = metrics.widthPixels;
float fourToThree;
int wymiar;
Bitmap mbitmap; //definicja zmiennej przechowującej bitmapę
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), cardBase.cardImages[position]);
mbitmap = Bitmap.createScaledBitmap(myBitmap, width, height, true);
myWallpaper.setBitmap(mbitmap);
Toast.makeText(SelectedCard.this, "Wallpaper changed \n" + width + "\n" + height, Toast.LENGTH_LONG).show();
}
catch (IOException e) {
e.printStackTrace();
Toast.makeText(SelectedCard.this, "Sorry, an error occurred", Toast.LENGTH_LONG).show();
}
}
});
Width and height values are correct 320 x 480 but image which I'm setting as a wallpaper is still more bigger then my device scren.
After test on my real phone LG L5 with new android (not sure which version). Image is set as wallpaper correct (in portrait mode - 1 image for all 5 "roll screens" without scaling).
How can i tested it on other devices ?
Mean... is this portrait mode for wallpapers is available only in new android version ?
Try this may work :
ImageView property :android:scaleType=“fitXY”
There are 2 ways to scale bitmap to fit a screen:
1st:
the follow function draws the specified bitmap, scaling/translating automatically to fill the destination rectangle:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect src, dst;
int widthOfBitmapSrc, heightOfBitmapSrc;
widthOfBitmapSrc = mBitmapSrc.getWidth();
heightOfBitmapSrc = mBitmapSrc.getHeight();
src = new Rect(0, 0, widthOfBitmapSrc, heightOfBitmapSrc);//size of bitmap
dst = new Rect(0,0,this.getWidth(),this.getHeight());//size of this view
canvas.drawBitmap(mBitmapSrc, src, dst, null);//scale bitmap from src to dst
}
see this link:http://developer.android.com/reference/android/graphics/Canvas.html
2nd:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int widthOfNewBitmap, heightOfNewBitmap;
widthOfNewBitmap = this.getWidth();//width of this view
heightOfNewBitmap = this.getHeight();//height of this view
Bitmap newBitmap = Bitmap.createScaledBitmap(mBitmapSrc, widthOfNewBitmap,heightOfNewBitmap,true);
canvas.drawBitmap(mBitmapSrc, 0, 0, null);//copy bitmap to canvas of this view without scale
}

Camera preview always returns a 320x240 Bitmap

I am creating an image preview and I wished to get a very high picture resolution. However, and I don't know why, despite Galaxy Nexus supports a wide range of resolutions (I think the largest one is 1920x1080, but I can't remember if those are the exact values), when I save the picture, it says the info coming from the preview is of 320x240.
pixels.mCamera = getCameraInstance();
Camera.Parameters params = mCamera.getParameters();
List<Size> sizes = params.getSupportedPreviewSizes();
Size biggestSize = sizes.get(0);
double biggestPixels = biggestSize.width + biggestSize.height;
for (Size size : sizes) {
double pixels = size.width * size.height;
if (pixels > biggestPixels) {
biggestSize = size;
biggestPixels = pixels;
}
}
// At this point, biggestSize is 1920x1080
float ratio = ((float) biggestSize.width)
/ ((float) biggestSize.height);
params.setPreviewSize(biggestSize.width, biggestSize.height);
mCamera.setParameters(params);
setCameraDisplayOrientation(this, 0, mCamera);
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
LinearLayout innerWrapper = (LinearLayout) findViewById(R.id.innerWrapper);
LayoutParams layoutParams = (LayoutParams) innerWrapper
.getLayoutParams();
layoutParams.height = (int) (layoutParams.height * ratio);
innerWrapper.setLayoutParams(layoutParams);
preview.addView(mPreview);
That innerWrapper stuff is to show a square picture. setCameraOrientation turns the image to align with the ratio. When taking the picture I use autofocus and then...
mCamera.autoFocus(new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
mCamera.takePicture(null, null, new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
data.length, options);
Bitmap finalBitmap;
float ow = bitmap.getWidth();
float oh = bitmap.getHeight();
// At this point, ow and oh are 320 and 240
float ratio = ow / oh;
int fw, fh, x, y, angle;
//It continues, but irrelevant
...
Is this anything related to the layout dimensions of the FrameLayout I use to hold the preview? Because I defined it to be of 350x350 dp, and this the preview should be bigger.
Silly me. The problem is that my PictureCallback is implemented as the jpeg parameter, not the raw one. Where, quoting the documentation:
The raw callback occurs when the raw image data is available (NOTE:
the data will be null if there is no raw image callback buffer
available or the raw image callback buffer is not large enough to hold
the raw image). The postview callback occurs when a scaled, fully
processed postview image is available (NOTE: not all hardware supports
this). The jpeg callback occurs when the compressed image is available.
Moving the whole PictureCallback to the second parameter of mCamera.takePicture instead of the third would be on the path to solve the issue. However, you'd need a CallbackBuffer to do so and change the code to adapt to the use of buffers. So for the first version I'll stick to low quality pictures.

Best way to scale size of camera picture before saving to SD

The code below is executed as the jpeg picture callback after TakePicture is called. If I save data to disk, it is a 1280x960 jpeg. I've tried to change the picture size but that's not possible as no smaller size is supported. JPEG is the only available picture format.
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream out = null;
Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
Bitmap sbm = Bitmap.createScaledBitmap(bm, 640, 480, false);
data.Length is something like 500k as expected. After executing BitmapFactory.decodeByteArray(), bm has a height and width of -1 so it appears the operation is failing.
It's unclear to me if Bitmap can handle jpeg data. I would think not but I have seem some code examples that seem to indicate it is.
Does data need to be in bitmap format before decoding and scaling?
If so, how to do this?
Thanks!
On your surfaceCreated, you code set the camara's Picture Size, as shown the code below:
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
try {
camera.setPreviewDisplay(holder);
Camera.Parameters p = camera.getParameters();
p.set("jpeg-quality", 70);
p.setPictureFormat(PixelFormat.JPEG);
p.setPictureSize(640, 480);
camera.setParameters(p);
} catch (IOException e) {
e.printStackTrace();
}
}

Categories

Resources