Android SurfaceView Canvas renders wrong colors - android

Hej guys, so this is the first time in about 7 years that I have not been able to find an answer to a programming issue, nor have I gotten close to what the issue might be in the first place.
Alright so let's begin from the start. I've followed some tutorials and examples on the Android SurfaceView and how to draw on its Canvas in another thread. So far, no issues, everything draws like I expect. I'm currently working on a scenario where I have some padding around my SurfaceView, which means that the background of the parent view (a FrameLayout) renders around the aforementioned SurfaceView. This is where things become interesting as I use the same color for the parent background as I do for clearing the SurfaceView's Canvas.
The root (=parent) FrameLayout has its background set in the theme like
<item name="android:windowBackground">#color/palette_primary_dark</item>
which is defined in colors.xml like
<color name="palette_primary_dark">#28252C</color>
and in my thread constructor, I retrieve the same color into the global variable mClearColor like
mClearColor = ContextCompat.getColor(context, R.color.palette_primary_dark);
where the context is the Context I receive from my SurfaceView.
The following code is the render loop that runs in my thread
#Override
public void run() {
while (mShouldRun) {
Canvas canvas = null;
try {
canvas = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
if (canvas != null) {
canvas.drawColor(mClearColor);
onDrawFrame(canvas);
}
}
} finally {
if (canvas != null) {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
So far, so good. No errors and everything draws; the background isn't black and it looks like the color I want. But here's the catch, it ISN'T actually the color I want. It's off by a hair. The color I defined in my XML is #28252C but according to my GIMP color picker tool it actually draws #292429. Weird.
Then I started searching further and discovered that the color I'm using to draw touch indicators (where my fingers are located on the screen) should be #FF1744 but actually is #FF1442.
This left me scratching my head and desperately trying other ways of drawing the right color on my canvas. I've tried Canvas.drawColor(), Canvas.drawARGB() and Canvas.drawRGB(), but to no avail. In drawColor() I even tried different ways of retrieving my color, like mClearColor, Color.parseColor("#28252C"), Color.argb(255, 40, 37, 44) and so on. Nothing worked.
Then I came across the fact that drawColor() uses PorterDuff.Mode.SRC_OVER by default, so I tried using PorterDuff.Mode.SRC to get the pure color I'm feeding it, but no happy faces :(
Then I just started trying stuff but nothing seemed to work. When I tried setLayerType() in my SurfaceView, something did change though. The following screenshot shows how it looked like with the default LAYER_TYPE_NONE value
LAYER_TYPE_NONE
Now when I change this to either LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE the same layout looks like follows
LAYER_TYPE_SOFTWARE/HARDWARE
The weird thing is now that it actually is the correct color and renders how I want it to, it still doesn't draw the lines and info about the touch. Calls to my onTouchListener are still being made, which in its turn should provide data to draw the lines on the screen. The latter doesn't work though, it doesn't actually draw the lines. I have no clue what causes this weird issue that changes my colors... Any help would be greatly appreciated :)
Edit #1:
I have done some more research today and as per this answer by Romain Guy and the following self-answered question by Adrian Lopez, setLayerType() actually does more harm than it solves problems. So I now have even less pointers as to what could cause or solve my issue :/ I'll make sure to edit the question when I have found more information and answer it if I found a solution :)

The SurfaceView's surface is configured to use RGB 565 by default.
In onCreate(), set the color format of the surface with setFormat() to get RGB 8888 instead:
mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT);

Related

Drawing Transparent lines on Bitmap Android

so I am running into an issue when I'm trying to create transparent lines in my android drawing app. My desired functionality is for these transparent lines' alpha channels to remain consistent as I continue to draw. What is happening is that the transparent line is being created, but as I continue to draw with the same line, the opacity of the older parts of the line begins to increase. I added a sample of this and also the code snippets that correlate with this. I have tried playing around with the PorterDuffXfermode however it seems to yield the same result or the transparent line overwrites the lines it draws over. Any ideas, hints or links would totally be grateful. Cheers!
Code
Drawing
It looks like you are drawing over the faded line over and over in touchedMove(). As a result you line gets darker where there has been more overdraw and lighter where there has been less.
I would do all drawing in onDraw() or draw(). You invalidate the view, so continue to do that and draw only once. If you want to continue with what you have, only draw the portion of the line that the motion event represents.

Android Custom View Flickering

I've been trying to solve my problem for a long time now. However, I'm at a loss. The problem is this:
I have a Custom Android View that I render 10 rectangles on(kind of
like a bar chart all the same length, different color)
When updating one of the rectangles with different opacity, it
doesn't change. So I clear the Canvas. But this causes a flicker,
not all the time, but sometimes
What I've tried doing:
Render everything to an offscreen bitmap, then blting it, this still
doesn't solve my issue
Use a SurfaceView and render in another thread
A combination of 1 and 2
In the end, I think the problem is that the background gets erased, but I don't want it to erase. However, I can never get the new "pixels" to show up. I also tried experimenting with different transfer modes like SRC, SRC_ATOP, when I tried number 1, it helps, but does not get rid of the problem.
Does anyone have any guidance on what could be going wrong? Or any other possible solutions?
I have finally figured it out. I don't have to clear the back ground, just temporarily change the paint mode to SRC.
context.paint.setStyle(Paint.Style.FILL);
context.paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
context.canvas.drawPath(context.path, context.paint);
context.paint.setXfermode(null);

android canvas draw text partial

on a canvas is it possible to draw text but make half of it not show up (as if it is being drawn partially off of the canvas, but actually not being off the canvas). i have an indicator on a "graph" with some text and it follows the point but I do not want the text to be drawn out of the graph portion (i am drawing other stuff outside that area).
I also have a background on the layout behind the canvas so I cannot just paint with a bitmap because that would cause some aspect ratio/sizing issues (wouldn't look good).
I have tried looking for answers all over Google, Stack overflow, and by experimentation with no avail. On Google I found many interesting things about drawing text on an android canvas but nothing that I was looking fore, I am pretty stumped, and I am starting to think that what I want is not even possible, and i may need to draw the text custom with points or figure out an alternative that looks just as good.
It's absolutely possible. Probably the fastest is to use clipRect to limit drawing to your graph portion. See this answer: Using clipRect - explanation
The reference on the various forms of clipRect is here: http://developer.android.com/reference/android/graphics/Canvas.html#clipRect(android.graphics.Rect, android.graphics.Region.Op)
If I recall, the whole operation will look something like:
yourCanves.save()
yourCanvas.clipRect(...)
yourCanvas.drawText(...)
yourCanvas.restore()
The restore() call serves to undo the clipRect so you can draw outside it for later drawing.
The simplest solution that popped in my mind, would be to cut using substring the text that you want to dispaly.
Example:
if(MyString >5){
canvas.drawText("VeryLongTe...");
}

How to show reflection of textures in libgdx?

I need to create an OpenGL ES app (preferably using libGDX) that shows a spinning texture that has a reflection of some sort beneath it.
I've searched the web, and found some very old tutorials of how to do it in OpenGL.
I'm wondering if there is an easy way to do it on libGdx or on Android, and if I'm forced to use OpenGL 2 instead of 1.x.
Is there any tutorial of achieving reflection of a texture in Java, Android or libgdx?
I've made some small progress, but I still need more help.
Currently the code of showing the texture is based on this link, and I've modified it so that it would show the spinning image and its reflection.
However, I have some bad issues with it:
it's almost like a perfect mirror. I need to put some kind of special effect so that it has some kind of gradient effect on it.
the images might go over one another, and they are not transparent. If I move the reflection a bit closer to the spinning image, I could see that they overlap each other.
The code is here:
public class GlRenderer implements Renderer
#Override
public void onDrawFrame(final GL10 gl)
{
gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
square.draw(gl);
// draw normal spinning image
gl.glLoadIdentity();
gl.glColor4f(1f,1f,1f,1f);
gl.glTranslatef(0.0f,0.0f,-5.0f);
gl.glRotatef(rotationAngle++,0.0f,0.0f,1.0f);
square.draw(gl);
// draw reflection
gl.glLoadIdentity();
gl.glColor4f(0.5f,0.5f,0.5f,1.0f);
gl.glTranslatef(0.0f,-1.0f,-3.0f);
gl.glRotatef(-80+180,1.0f,0.0f,0.0f);
gl.glRotatef(rotationAngle,0.0f,0.0f,1.0f);
}
Is there anyone that could help me on this?
For a perfect effect you will need to do 2 things.
Assuming you used Image class to render it,
first, is to put the same image bellowthe original one and use the scaleY to flip it vertically.
this will create reflection effect, but you will need to apply same things that you applied to first image to the second one, like movement, rotation, whatever you did to it.
Besides that you will probably need your reflection image to fade out like a gradient, if you are doing everything on a solid not moving background, you can create a third image which is a gradient png from transparent to the color of your background, and put it over the reflection image. If you have a dynamic background, then you will probably need to use shaders (sorry, openGL 2 only). You can read more on how to write custom shaders here: http://blog.josack.com/2011/08/my-first-2d-pixel-shaders-part-3.html (A great tutorial)]
Hope that helps. There might be other solution I don't know about, so keep researching, but this is what came to my mind.

android Paint.setShadowLayer() vs Canvas.drawbitmap() problems

I use the following code to draw a bitmap during onDraw of a custom View
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
p.setShadowLayer(3,3,3,0xff000000);
Bitmap bmp = BitmapFactory.decodeResource(some drawable jpg);
canvas.drawBitmap(bmp,null,new Rect(blah blah),p);
and the shadow looks funny. What do I mean funny? I mean that I get a different shadow then if I was calling canvas.drawRect(). It looks sorta like the android shadow code is treating the bitmap as an alpha channel or something.
have tried adding p.setColor(0xff000000); and p.setStyle(Paint.Style.FILL); but not difference.
I guess I could drawRect with shadow on, then drawBitmap with shadow off, but that seems silly as it would be rendering pixels twice.
Basically the shadow layer doesn't work for anything except text. It's real dumb. Check the Android hardware acceleration supported operations chart.
This question was asked back in 2010 when hardware accelerated view trees didn't exist.. based on things I've read, even then the shadow layer only worked for simple shapes (if at all), and others got weird results using it on anything but text. You might be out of luck.
Finally, there are many ways you can fake a shadow layer. You can wrap a view in another view and draw underneath it. You can write a view that draws the shadow yourself as a radial gradient, etc. But you probably just want to make a 9patch that looks like a shadow and use that.
2018 Update
It looks like most of the operations are supported as of api 28! I haven't had a chance to play around with shadow layers recently, but things are looking much more optimistic now.
Maybe http://developer.android.com/reference/android/graphics/Paint.html#isAntiAlias()
can help you.
paint.setAntiAlias(true);
Maybe you should have different Paint objects for different purposes like text, bitmap, etc. So one's setting will not affect others.

Categories

Resources