Android gradient graphics quality (scaled bitmap) - android

I want to display a splash screen with an gradient in my app. But the quality of the gradient in the background is pretty bad. So I create a simple radiant gradient to have a closer look.
Edit: Maybe I should have mentioned that I am using BitmapFactory.createScaledBitmap(); and BitmapFactory.decodeStream() (The graphics are in the assets folder.)
Thats the result:
Original *.jpg (Quality 100%)
Screenshot Xperia X10 (I took the screenshot with Eclipse)

You can do it without any jpg file, but using a shape drawable. Create rectangle and provide necessary parmas for gradient tag.

In order to scale a bitmap and keep ARGB_8888 I created a new bitmap in the desired size. Then I use canvas to draw the intrinsic bitmap on the new bitmap with drawBitmap. This method allows me to scale the bitmap before I draw it on the new bitmap.
inputStream = assetManager.open(path);
originalBitmap = BitmapFactory.decodeStream(inputStream, null, opts);
Bitmap resizedBitmap = Bitmap.createBitmap(desiredX, desiredY, Config.ARGB_8888);
Canvas canvas = new Canvas(resizedBitmap);
canvas.drawBitmap(originalBitmap, null, new Rect(0, 0, desiredX, desiredY), null);
inputStream.close();
return resizedBitmap;

Related

How to draw an image on top a bitmap and combine as one bitmap in Android Java

I am developing an Android application using Java. I am doing some image manipulating in my application. First of all, I like to save I have no knowledge about image processing. But, I am trying to get into it. What I would like to do now is draw a simple image on a bitmap and save it as one bitmap.
I am loading an image from asset folder as a bitmap like this.
Bitmap rectBitmap = BitmapFactory.decodeStream(istr);
Let's say the photo is a just simple rectangle like this.
Then I would like to draw a bitmap (triangle shape) using coordinates point. The image would be some this.
My imagination of code would be like this.
rectBitmap.drawOnTop(coorPointOneValues, coorPointTwoValues, coorPointThreeValues);
Coordinate point values would be x and y value since I am working on the 2D coordinate system.
Then I would like to save the image something like this after drawing traingle
rectBitmap = rectBitmap.saveBitmap();
How can I do it? The scenario mentioned is a possible way that I can think of. If it is not possible, what would be the other way around?
You can do it like this.
1, read or create your bitmap:
Bitmap rectBitmap = BitmapFactory.decodeStream(istr);
Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
2, create a canvas on the bitmap:
Canvas canvas = new Canvas(bitmap);
3, draw something:
canvas.drawColor(Color.RED)
canvas.drawRect / canvas.drawLine / canvas.drawArc ...
//for triangle shape you can use drawPath
4, save the bitmap:
bitmap.compress(CompressFormat format, int quality, OutputStream stream)

Android Canvas DrawBitmap poor quality

I'm extending SurfaceView to create a fullscreen horizontally scrollable background.
My issue is with the quality of the bitmap. When used in the draw-call as
canvas.drawBitmap(bitmap, 0, 0, paint);
It's quality is much poorer than its original. I'm not doing any scaling.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image, options);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setFilterBitmap(true);
Not sure if the images show it clearly, they're screenshots from the tablet. The good one is an ImageView with its src as the drawable.
The canvas one has this horizontally stripy effect, its very significant in reality. This effect is vertical as well. It's whenever the gradient is slightly changing. As if the canvas' bitmap has much less colors..
I'm sure there's a solution to this, but I could not find any.
Poor quality example
Real quality example
Looks like color quantization. The default color format for SurfaceView is 16-bit RGB_565. Change it to 32-bit with something like this on onCreate():
mSurfaceView.getHolder().setFormat(PixelFormat.RGBA_8888);
(Some examples use PixelFormat.TRANSLUCENT.)

Using NinePatch (.9.png) for making scaled Bitmaps

I need to draw a Bitmap for my new Android Application. Since my content view is set to a Game-Panel class I've created. I want to display images through Bitmap. Just because its more convenient, and easier to do then anything else.
From what I've gathered from researching, Nine Patch images (.9.png) are used in android to scale more properly then regular Drawable images. It also says "This can be used for scaling properly in backgrounds. For example a regular button background...". If Nine Patch images are made to scale better. Can You use a Nine Patch for making a Bitmap in a specific width and height because it would scale more properly? For example
Bitmap b = createBitmap(BitmapFactory.decodeResource(NinePatchImage), x, y, width, height);
Is this possible? Should I do it a different way? Should I create a bitmap first and then just scale the bitmap? Is this even necessary? Please help.
Bitmap bitmap = Bitmap.createBitmap(canvasWidth, canvasHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
NinePatchDrawable drawable = (NinePatchDrawable) getResources().getDrawable(R.drawable.myDrawable);
drawable.setBounds(new Rect(x, y, width, height));
drawable.draw(canvas);

Set Picture into RemoteViews

I have some SVGs in my assets folder and I need to dynamically set them in my widget (on an ImageView).
I am using this library: http://code.google.com/p/svg-android/
This library returns a Picture or a PictureDrawable.
The only methods I can see to use on RemoteViews are setImageViewBitmap which obviously takes a bitmap.
I tried looking for code to convert a Drawable to a Bitmap like this:
PictureDrawable pictureDrawable = svg.createPictureDrawable();
Bitmap bitmap = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(), pictureDrawable.getIntrinsicHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawPicture(pictureDrawable.getPicture());
currentBitmap = bitmap;
But the bitmap is too small. When I create the bitmap in Illustrator I set the artboard size to 65 which is what comes through on the intrinsic width/height.
My widgets can be resized so the ImageView sizes are variable. Even if I set the width and height statically to some large number like this...
Bitmap bitmap = Bitmap.createBitmap(300, 300, Config.ARGB_8888);
then the resulting bitmap just has a bunch of whitespace below and to the right of a tiny image.
I guess I need to somehow draw the picture at a scaled up value as well as creating the Bitmap at size 300. Ideally I could figure out the size of the ImageView at runtime and set the proper sized Bitmap if I knew that. Is this the best approach and how would I do this? Perhaps there is a better approach I don't even know about?
I've not used android-svg but if it's using vanilla PictureDrawables, then it should be just a matter of not using the intrinsic bounds.
Try the following:
PictureDrawable pictureDrawable = svg.createPictureDrawable();
Bitmap bitmap = Bitmap.createBitmap(300, 300, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
pictureDrawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
pictureDrawable.draw(canvas); // do not access the Picture directly, that defeats the purpose
currentBitmap = bitmap;
In short, use the Drawable, not its Picture and set the Drawable's bounds to be the full canvas.
Have you tried createScaledBitmap?
createScaledBitmap()
I have tried svg-android and it has not worked for me for this very reason. Not to mention its severely limited feature set.
The point of using vector graphics is that I can generate images of any appropriate size to fit the UI View size. Which means the generation method must accept the size requirements at run-time, and not always use width,height declared in <svg> tag.
Hence I used the native implementation: libsvg-android, which exactly does that.
It directly renders to a canvas with given size:
long objId = SvgRaster.svgAndroidCreate();
SvgRaster.svgAndroidParseBuffer(objId, readString(mInputStream, "UTF-8"));
SvgRaster.svgAndroidSetAntialiasing(objId, true);
SvgRaster.svgAndroidRenderToArea(objId, mCanvas, 0, 0, mWidth, mHeight);
I ended up modifying the underlying Artboard size to be 300. None of the scaling up methods worked. So the final code I used was that which I originally posted:
PictureDrawable pictureDrawable = svg.createPictureDrawable();
Bitmap bitmap = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(), pictureDrawable.getIntrinsicHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawPicture(pictureDrawable.getPicture());
currentBitmap = bitmap;
Once I had a 300x300 Bitmap I was able to set it into the RemoteViews using setImageViewBitmap .
This kind of defeated the purpose of using SVGs in the first place (at least as far as using them in widgets was concerned).
My problem was not the same as User117. Perhaps he did not name the outer layer 'bounds' as was required in the library. Either way, I managed to get the library working, albeit by having to modify the SVG Artboard size.
Hopefully with the increase in screen resolution Android will introduce SVGs as part of the platform soon.

Rotating a bitmap using matrix

While rotating a bitmap using matrix, vertex is not stable..
Matrix matrix = new Matrix();
matrix.postRotate(mDegree,100,100);
mCompasstemp = Bitmap.createBitmap(mCompPic, 0, 0, mCompPic.getWidth(), mCompPic.getHeight(), matrix, true);
mCompassHud.setImageBitmap(mCompasstemp);
Output of my code is like
-bitmap will rotate.
-vertex of my bitmap is not stable.
-Bitmap is resizing
I need disable image resizing and make the rotation stable.Can you please suggest a solution for this?
Rather than creating your new Bitmap directly from the original, another (more straight-forward, imho) option is to create the resultant Bitmap, create a Canvas with that Bitmap, then do your rotation/translation/scaling on the Canvas and draw the original Bitmap onto the new Bitmap via the Canvas.
Basically, you're looking, then, at:
scaledImage = Bitmap.createBitmap (croppedWidth, croppedHeight, Bitmap.Config.ARGB_8888);
Canvas offscreenCanvas = new Canvas (scaledImage);
Matrix matrix = new Matrix();
matrix.setRotate (rotations, centreX, centreY);
matrix.postScale(scaleX, scaleY);
offscreenCanvas.setMatrix (matrix);
offscreenCanvas.drawBitmap (pickedImage, 0, 0, new Paint(Paint.DITHER_FLAG));
Not sure if this is what your looking for but it might help.
Android uses its built in compatibility features to scale and render a bitmap appropriately for screens with different pixel densities. There are two methods of scaling, pre-scaling and auto-scaling.
It will pre-scale bitmaps' from resources and auto-scales when the bitmap is being drawn internally (which is what your doing be using createBitmap).
Go to http://developer.android.com/guide/practices/screens_support.html and check under:
4.Use density and/or size-specific resources:
Pre-scaling and auto-scaling of bitmaps and nine-patches
I have tried this code, and the rotate is stable at the center of the bitmap
matrix.reset();
matrix.setRotate(degree, Xpos+bitmap.getWidth()/2, Ypos+bitmap.getHeight()/2);
and then in canvas doDraw()
canvas.setMatrix(matrix);
canvas.drawBitmap(bitmap, Xpos, Ypos, null);
canvas.setMatrix(null);
The Xpos and Ypos is the X and Y position of the bitmap
The setMatrix(null), set the matrix to null, so that the rotate didn't affect the after bitmap
And it didn't always create new bitmap, so it's great for performance
I hope that help
I know its an old question but, all answers with code imply a canvas, so heres a solution without a canvas that worked for me :
Matrix matrix = new Matrix();
matrix.postRotate(mDegree,100,100);
mCompasstemp = Bitmap.createBitmap(mCompPic, 0, 0, mCompPic.getWidth(),
mCompPic.getHeight(), matrix, true);
mCompasstemp = Bitmap.createScaledBitmap(mCompassTemp, mCompPic.getWidth(),
mCompic.getHeight(), false);
mCompassHud.setImageBitmap(mCompasstemp);
So basically after rotating your bitmap you rescale it to the desired size. Might not be best practice, but at least you dont have to create an extra canvas if you dont want/need to, since the involving Paint() Object is not an inexpensive operation either.

Categories

Resources