My problem is that when drawing a simple test image (a rectangle with a gradient fill) within a SurfaceView, the gradient has colour banding. When drawing exactly the same rectangle with the same gradient in a simple extended View, the gradient looks very smooth, and as nice as I would expect for 32-bit colour.
This is occurring side by side using the test SurfaceView placed alongside the test View within the same layout in the same Activity.
For information, in the Activity class I am calling window.setFormat(PixelFormat.RGBA_8888) to switch the Activity to 32-bit colour, as this was the solution in the past to eliminate banding in gradients (however, I believe that this is no longer necessary at a certain Android level, where 32-bit is the default). My minSdkVersion is 8.
The test code that appears in the onDraw() of both the simple extended View and the SurfaceView is:
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(false);
paint.setFilterBitmap(false);
paint.setDither(false);
Shader shader = new LinearGradient(
0,
0,
0,
200,
new int[]{0xff150d2f,0xff432b96},
null,
Shader.TileMode.CLAMP
);
paint.setShader(shader);
canvas.drawRect(0,0,getWidth(),getHeight(), paint);
Here is the screenshot showing the SurfaceView above and the normal View beneath. I realise that the banding is very subtle in this example; it's even more apparent when the gradient sweeps over a smaller band of colours.
Any suggestions, please?
Trev
Found the solution myself in the end by adding this into the SurfaceView's constructor:
getHolder().setFormat(PixelFormat.RGBA_8888);
Related
let's get straight to the point, I was making an android game and I decided to try and use some more android methods like Rect and Path so I can experiment and learn how they work. (in the past I used only bitmaps to draw graphics)
As I was making the game I noticed some weird coloring on my rects, so I tried a lot of things, I made sure my rects are initialized properly and I also tried to simplify my code to make sure the problem was caused there.
For debug purposes my code draws a white square on the top left side of the screen, a black on the top right, and a gray one on the bottom, this is the code:
Paint pGray, pWhite, pBlack;
public myClass()
{
paintGray = new Paint();
paintGray.setARGB(255, 125, 125, 125);
paintWhite = new Paint();
paintWhite.setARGB(255, 255, 255, 255);
paintBlack = new Paint();
paintBlack.setARGB(255, 0, 0, 0);
}
public void draw(Canvas canvas)
{
canvas.drawRect(0, screenHeight/2, screenWidth, screenHeight, paintGray);
canvas.drawRect(0, 0, screenWidth/2, screenHeight/2, paintWhite);
canvas.drawRect(screenWidth/2, 0, screenWidth, screenHeight/2, paintBlack);
}
(I don't know if it matters but it runs on another Thread)
When I run it on my phone and save a screenshot using Android Studio the screenshot looks like this:
which is t he desired result, the problem is that my phone doesn't display the graphics properly and here is a photo:
As you can see the gray square has 2 colors inside it, a darker and a lighter one. It happens on both phones that I have and I have no idea what it is, even weirder is that saving the screenshot doesn't show this problem!!
I also noticed the colorization changes based on the white square, if I make it bigger or smaller the gray square changes its color where the white box ends.
Another thing I noticed is that these lines of "decolorization" (with multiple white boxes, multiple lines appear) on the gray square is vertical on landscape mode, but on portrait it becomes horizontal.
I've been torturing my self for so much time with this, I have commented out my whole application to try and see why it happens, if I'm missing something or anyone knows anything please let me know!
I don't think it's a software bug. My guess would be that that's the way the display is rendering colors.
Imagine that I have a rectangle image. How could I create a style like the next one?
I mean, cropping the image into a circle, add the border, the shadow and the gross /shine effect. Until now, I only have tried this snippet code to crop the image: Cropping circular area from bitmap in Android but just that. I have no idea how to do the remaining components in Android.
An easy way to achieve this effect is to use Canvas.drawCircle() and a BitmapShader:
BitmapShader s = new BitmapShader(myPhoto, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint p = new Paint();
p.setShader(s);
myCanvas.drawCircle(centerX, centerY, radius, p);
To do the shadow, simply call Paint.setShadowLayer() on the paint (this will only work if you draw the effect into an offscreen Bitmap or if your View uses a software layer – set by calling View.setLayerType() –).
The border can be drawn by drawing another circle on top, using the Paint.Style.STROKE style (that you can set by calling Paint.setStyle()).
Finally you can draw the gloss by drawing a circle, oval or Path on top of your very first circle. You'll need to use a LinearGradient shader on your paint and you'll also need to clip the gloss. You can do this in two ways:
If you are drawing the entire effect into a Bitmap, which is what I would recommend, simply set the paint's Xfermode to a new PorterDuffXfermode(PorterDuff.Mode.SRC_IN).
If you are drawing the effect directly on screen you can simply use Canvas.clipPath() to set a circular clip. Note that this will work with hardware acceleration only as of Android 4.3.
The goal is to create a composite shape and add an emboss effect. I can successfully create the shape as illustrated below.
woodPaint = new Paint();
woodPaint.setAntiAlias(true);
woodBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.wood);
woodShader = new BitmapShader(woodBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
woodPaint.setShader(woodShader);
...
#Override
protected void onDraw(Canvas canvas) {
canvas.drawCircle(handleX, radius, radius, woodPaint);
canvas.drawRoundRect(baseRectF, 25, 25, woodPaint);
super.onDraw(canvas);
}
Image:
Then I add an EmbossMaskFilter
paintEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.1f, 8f, 5f);
woodPaint.setMaskFilter(paintEmboss);
Image:
As you can see the emboss mask is applied to the two shapes separately. How can I compose the shapes together and apply the emboss to the entire object? I've tried setting the xfer mode to some flavor off porter duff but this doesn't effect the fact that the emboss mask is applied to each shape separately.
Thanks for any help!
Edit:
As illustrated by Orabîg, you must draw one path with the paint that you've set an emboss filter on. NOTE: the method setMaskFilter() is one of the handful of methods that don't work when hardware acceleration is turned on. I resolved an issue I was having with a phone running jelly bean by disabling hardware acceleration for the activity. You can disable hardware acceleration at any level you choose:
ApplicationActivityWindowView
Cheers!
Well, you need only one emboss effect, so you should ony draw one shape.
So you should use the Canvas.drawPath() method.
You'll just have to define a Path object, with the following methods :
Start by defining 3 RectF objects, which will be the bounding boxes of the left-most round (imagine the circle behind it), the right-most one, and the sliding one :
You'll maybe have to do some additional maths to determine the correct angles to use for box2 (they depend on the respective size of the circle and the whole rectangle)
Good luck !
I have an 8x8 Image. (bitmap - can be changed)
What I want to do is be able to draw a shape, given a Path and Paint object onto my SurfaceView.
At the moment all I can do is fill the shape with solid colour. How can I draw it with a pattern.
In the image you can see the brush pattern (The cross). It can be anything from a cross to a donut or an elf.
How would I go about drawing this pattern background.
I also eventually want to apply colours to it.
So far, my theory is to create a clip area of the shape, and tile the bitmaps until area is covered, but this is extreme overkill in processing. Nor sound ideal.
In terms of colouring, I can edit the brushes to be alpha, fill the same with background colour, then draw the images on top. The real issue it the tiling of such patterns.
Ive found a few questions of a similar nature, all unanswered, and/or not applicable to my situation. (use of xmls on views etc)
Did you checked this blog. Its using BitmapShader
Example:
//Initialize the bitmap object by loading an image from the resources folder
fillBMP = BitmapFactory.decodeResource(m_context.getResources(), R.drawable.cross);
//Initialize the BitmapShader with the Bitmap object and set the texture tile mode
fillBMPshader = new BitmapShader(fillBMP, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
fillPaint.setStyle(Paint.Style.FILL);
//Assign the 'fillBMPshader' to this paint
fillPaint.setShader(fillBMPshader);
//Draw the fill of any shape you want, using the paint object.
canvas.drawCircle(posX, posY, 100, fillPaint);
My problem is that when drawing a simple test image (a rectangle with a gradient fill) within a SurfaceView, the gradient has colour banding. When drawing exactly the same rectangle with the same gradient in a simple extended View, the gradient looks very smooth, and as nice as I would expect for 32-bit colour.
This is occurring side by side using the test SurfaceView placed alongside the test View within the same layout in the same Activity.
For information, in the Activity class I am calling window.setFormat(PixelFormat.RGBA_8888) to switch the Activity to 32-bit colour, as this was the solution in the past to eliminate banding in gradients (however, I believe that this is no longer necessary at a certain Android level, where 32-bit is the default). My minSdkVersion is 8.
The test code that appears in the onDraw() of both the simple extended View and the SurfaceView is:
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(false);
paint.setFilterBitmap(false);
paint.setDither(false);
Shader shader = new LinearGradient(
0,
0,
0,
200,
new int[]{0xff150d2f,0xff432b96},
null,
Shader.TileMode.CLAMP
);
paint.setShader(shader);
canvas.drawRect(0,0,getWidth(),getHeight(), paint);
Here is the screenshot showing the SurfaceView above and the normal View beneath. I realise that the banding is very subtle in this example; it's even more apparent when the gradient sweeps over a smaller band of colours.
Any suggestions, please?
Trev
Found the solution myself in the end by adding this into the SurfaceView's constructor:
getHolder().setFormat(PixelFormat.RGBA_8888);