How to get bitmap of whole screen with Libgdx? - android

I would like to know how can I get bitmap of whole current screen. I would like to check RGBA values of selected pixel. My code that isn't working properly:
public class PixmapTest implements Screen
{
//(...)
private float getRedValue(int x, int y)
{
Pixmap pixmap = new Pixmap(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Pixmap.Format.RGBA8888);
Color color = new Color();
Color.rgba8888ToColor(color, pixmap.getPixel(x,y));
pixmap.dispose();
return color.r;
}
#Override
public void render()
{
Gdx.gl.glClearColor(1f, 0f, 0f, 1f);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
System.out.println(getRedValue(50, 50));
}
}
It seems to me that the getRedValue method, should return 1.0, but it returns 0.0. I'm apologize for unproffesional question. I'm new to Libgdx and game development as well.

The easiest way is to use the ScreenUtils package, e.g.
Image screenShot = new Image(ScreenUtils.getFrameBufferTexture());

What you have done is you have created a blank pixmap that doesn't contain anything. Kumar Saurabh is right that you need to take the screen shot of that image and the function to get the pixel Value.
you can do it as
final Pixmap pixmap = new Pixmap(w, h, Format.RGBA8888);
ByteBuffer pixels = pixmap.getPixels();
Gdx.gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixels);
Color color = new Color();
Color.rgba8888ToColor(color, pixmap.getPixel(x,y));
pixmap.dispose();
return color.r;
Hope this might work for you

https://code.google.com/p/libgdx-users/wiki/Screenshots
This is how stuff works
Do not forget to get PNG.java class also as main logic is in it only
Also if u are using LibGdx 0.9.8 these classes are implicitly included in the gdx.jar

Related

How to create emboss around a Bitmap?

The popular game Words with Friends draws letter tiles at the game board as a single entity -
You can see a yellow linear gradient applied to all letter tiles in the following screenshot and also an emboss effect on the edge:
In my word game I would like to have similar effects:
So I create a game board sized mBitmap, then draw all tiles into it and finally draw the bitmap into my custom view -
Setup:
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
// create yellow linear gradient
mGradStart = new Point(3 * mWidth / 4, mHeight / 3);
mGradEnd = new Point(mWidth / 4, 2 * mHeight / 3);
LinearGradient gradient = new LinearGradient(
mGradStart.x,
mGradStart.y,
mGradEnd.x,
mGradEnd.y,
new int[]{ 0xCCFFCC00, 0xCCFFCC99, 0xCCFFCC00 },
null,
TileMode.CLAMP);
// create the big bitmap holding all tiles
mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPaintGrad = new Paint();
mPaintGrad.setShader(gradient);
mPaintEmboss = new Paint();
mPaintEmboss.setShader(gradient);
EmbossMaskFilter filter = new EmbossMaskFilter(
new float[] { 0f, 1f, 0.5f }, 0.8f, 3f, 3f);
mPaintEmboss.setMaskFilter(filter);
Drawing:
#Override
protected void onDraw(Canvas canvas) {
mGameBoard.draw(canvas);
// draw all tiles as rectangles into big bitmap
// (this code will move to onTouchEvent later)
mBitmap.eraseColor(Color.TRANSPARENT);
for (SmallTile tile: mTiles) {
mCanvas.drawRect(
tile.left,
tile.top,
tile.left + tile.width,
tile.top + tile.height,
mPaintGrad);
tile.draw(mCanvas);
}
canvas.drawBitmap(mBitmap, 0, 0, mPaintEmboss); // emboss NOT displayed
canvas.drawText("TEXT WORKS OK", 400, 400, mPaintEmboss); // ebmoss OK
canvas.drawRect(300, 600, 800, 1200, mPaintEmboss); // emboss OK
}
The EmbossMaskFilter effect works OK with drawText() and drawRect() calls, but it does NOT work for the drawBitmap():
My question: is it possible to use some combinations of PorterDuff.Mode (and extractAlpha?) to draw an emboss around my big bitmap?
UPDATE:
By looking at HolographicOutlineHelper.java I have been able to add an outer shadow:
with the following code in MyView.java -
Setup:
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mScale = getResources().getDisplayMetrics().density;
mGradStart = new Point(3 * mWidth / 4, mHeight / 3);
mGradEnd = new Point(mWidth / 4, 2 * mHeight / 3);
LinearGradient gradient = new LinearGradient(
mGradStart.x,
mGradStart.y,
mGradEnd.x,
mGradEnd.y,
new int[]{ 0xCCFFCC00, 0xCCFFCC99, 0xCCFFCC00 },
null,
TileMode.CLAMP);
mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPaintGrad = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
mPaintGrad.setShader(gradient);
mPaintBlur = new Paint();
mPaintBlur.setColor(Color.BLACK);
BlurMaskFilter blurFilter = new BlurMaskFilter(mScale * 1, Blur.OUTER);
mPaintBlur.setMaskFilter(blurFilter);
}
Drawing:
private void prepareBitmaps() {
mBitmap.eraseColor(Color.TRANSPARENT);
for (SmallTile tile: mTiles) {
mCanvas.drawRect(
tile.left,
tile.top,
tile.left + tile.width,
tile.top + tile.height,
mPaintGrad);
tile.draw(mCanvas);
}
mAlphaBitmap = mBitmap.extractAlpha(mPaintBlur, mOffset);
}
#Override
protected void onDraw(Canvas canvas) {
mGameBoard.draw(canvas);
canvas.drawBitmap(mAlphaBitmap, mOffset[0], mOffset[1], mPaintBlur);
canvas.drawBitmap(mBitmap, 0, 0, mPaintGrad);
}
but unfortunately the app is acting slow now - and I still don't know how to add an emboss effect around the bitmap.
I'm not sure i got exacly what you need, but if you just want to apply EmbossMaskFilter around some png letter with alpha channel, you can pretty much do this trick with
EmbossMaskFilter filter = new EmbossMaskFilter(new float[]{1, 1, 1}, 0.5f, 0.6f, 2f);
Paint paintEmboss = new Paint();
paintEmboss.setMaskFilter(embossMaskFilter);
Bitmap helperBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas helperCanvas = new Canvas(helperBitmap);
Bitmap alpha = src.extractAlpha();
helperCanvas.drawBitmap(alpha, 0, 0, paintEmboss);
alpha.recycle();
...
canvas.drawBitmap(helperBitmap, 0, 0, anyPaint);
You will never want all of this code in 1 onDraw, because it creates lots of objects in memory. And src.extractAlpha(); creates new Bitmap each time. (Btw i always get out of memory error from your project git . Added mAlphaBitmap.recycle(); and it could at least boot. But it still lagges like hell)
So, i played with your git repository and got some results. Here is demo image and git repo of first commit:
But then i realized, that you don't need EmbossMaskFilter around letters, you need them around rectangles. And it can be done pretty much the same way. Here is how i done this:
Create new helper static Bitmap and Canvas for emboss background, just like mAlphaBitmap
On each prepareBitmaps() paint rects on helper bitmap. Solid color with no alpha.
Extract alpha from created bitmap like this Bitmap alpha = helperCanvas.extractAlpha();
Draw extracted alpha bitmap on helper with paint with emboss filter helperCanvas.drawBitmap(alpha, 0, 0, paintEmboss);
In onDraw print helperBitmap with some alpha before main Bitmap.
Here is screenshot without alpha(because it is much easier to see the shapes this way)
Here is git demo of this version: https://github.com/varren/AndroidEmbossMaskFilterForPng/blob/1d692d576e78bd434252a8a6c6ad2ee9f4c6dbd8/app/src/main/java/de/afarber/mytiles2/MyView.java
And here is essential part of code i changed in your project:
private static final EmbossMaskFilter filter =
new EmbossMaskFilter(new float[]{1, 1, 1}, 0.5f, 0.6f, 2f);
private static Canvas helperCanvas;
private static Paint paintEmboss;
public Canvas getHelperCanvas(int width, int height){
if (mAlphaBitmap == null) {
mAlphaBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
helperCanvas = new Canvas(mAlphaBitmap);
paintEmboss = new Paint();
paintEmboss.setColor(Color.BLACK);
}
return helperCanvas;
}
private void prepareBitmaps() {
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
helperCanvas = getHelperCanvas(mBitmap.getWidth(),mBitmap.getHeight());
helperCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
paintEmboss.setMaskFilter(null);
paintEmboss.setAlpha(255);
for (SmallTile tile: mTiles) {
if (!tile.visible) continue;
helperCanvas.drawRect(tile.left,tile.top,tile.left + tile.width,
tile.top + tile.height,paintEmboss);
mCanvas.drawRect(tile.left, tile.top,tile.left + tile.width,
tile.top + tile.height, mPaintGrad);
tile.draw(mCanvas);
}
paintEmboss.setMaskFilter(filter);
Bitmap alpha = mAlphaBitmap.extractAlpha();
helperCanvas.drawBitmap(alpha, 0, 0, paintEmboss);
}
protected void onDraw(Canvas canvas) {
// ...
paintEmboss.setAlpha(255); //todo change alpha here
if(mAlphaBitmap!= null)canvas.drawBitmap(mAlphaBitmap, 0,0, paintEmboss);
if(mBitmap!= null)canvas.drawBitmap(mBitmap, 0, 0, mPaintGrad);
// ...
}
And the last 3-d step i made is to move everything from onDraw to prepareBitmaps() and preformance is fine now, but we have text destortion on resize. so here is source code for this step.
And here is kinda fine working final solution. Moving all paints with filters solved preformance issues, but i think there are still better options to implement this. As i said erlier i don't know is it what you need, but this code pretty much creates Emboss around Bitmap
PS: kinda cool effect when splitting and adding cells together
PS2: new EmbossMaskFilter(new float[] { 0f, 1f, 0.5f }, 0.8f, 3f, 3f); this will not look the same on diferent devices with diferent screen resolution
Here's a suggestion using a custom layout.
You'll need your own layout for the scrabble board. Since it's grid, this should be pretty easy to code.
The basic idea is to have a set of PNG shadow images, one for each type of combination of adjacent cells. In your layout onDraw(), draw the shadows first, then draw the tile in onLayout().
In onDraw(), iterate through your array of tiles placeholders. If you have a tile, then for each edge, inspect the adjacent cells. Depending on what's adjacent, choose the correct shadow image and draw it.
You can reduce the number of shadow images substantially by having a shadow image which is exactly the width of a tile and then specializing the corner area: one for 270 degrees, one for straight alignment, one for 90 degrees.
I don't know if using porter-duff can help since you still need to determine all these "edge" cases (no pun intended).

Dynamic texture creation with font using libgdx

I'm working on a word game and I was dynamically creating the textures for the letter tiles when the game loads, comprising of a background image and a font.
To do this I was drawing pixmaps onto pixmaps, this was all fine until I started working on scaling. The font scaling on the pixmaps was terrible, even with bilinear filtering turned on (left image below) even though my scaled fonts were looking pretty good elsewhere.
So I decided to get round this I'd use a frame buffer, render everything to that and then copy that out to a pixmap and create a texture from that. That way I could use the gpu filtering and it should look exactly the same as my other fonts, (middle image below) but it still didn't look quite as nice as the other fonts. A slight dark line round the outside, it looks like the alpha blending isn't working properly.
I then tried drawing straight over the tiles with the font at runtime to make sure it wasn't my imagination, and this definitely looks better with smooth blending into the image below (right image below), but this impacts my frame rate quite a lot.
So my question is, why is drawing to the frame buffer not producing the same result as when I draw to the screen? Code below.
Texture tx = Assets.loadTexture("bubbles/BubbleBlue.png");
tx.setFilter(TextureFilter.Linear, TextureFilter.Linear);
SpriteBatch sb = new SpriteBatch();
FrameBuffer fb = new FrameBuffer(Format.RGBA8888,
LayoutManager.getWidth(), LayoutManager.getHeight(), false);
fb.begin();
sb.begin();
sb.draw(tx, 0, 0, LetterGrid.blockWidth, LetterGrid.blockHeight);
Assets.candara80.font.getRegion().getTexture()
.setFilter(TextureFilter.Linear, TextureFilter.Linear);
Assets.candara80.setSize(0.15f);
TextBounds textBounds = Assets.candara80.getBounds(letter);
Assets.candara80.drawText(sb, letter,
(LetterGrid.blockWidth - textBounds.width) / 2,
(LetterGrid.blockHeight + textBounds.height) / 2);
sb.end();
Pixmap pm = ScreenUtils.getFrameBufferPixmap(0, 0,
(int) LetterGrid.blockWidth, (int) LetterGrid.blockHeight);
Pixmap flipped = flipPixmap(pm);
result = new Texture(flipped);
fb.end();
pm.dispose();
flipped.dispose();
tx.dispose();
fb.dispose();
sb.dispose();
set PROJECTION is the problem.
EXAMPLE
public Texture texture(Color fg_color, Color bg_color)
{
Pixmap pm = render( fg_color, bg_color );
texture = new Texture(pm);//***here's your new dynamic texture***
disposables.add(texture);//store the texture
}
//---------------------------
public Pixmap render(Color fg_color, Color bg_color)
{
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();
SpriteBatch spriteBatch = new SpriteBatch();
m_fbo = new FrameBuffer(Format.RGB565, (int)(width * m_fboScaler), (int)(height * m_fboScaler), false);
m_fbo.begin();
Gdx.gl.glClearColor(bg_color.r, bg_color.g, bg_color.b, bg_color.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
/**set PROJECTION**/
Matrix4 normalProjection = new Matrix4().setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
spriteBatch.setProjectionMatrix(normalProjection);
spriteBatch.begin();
spriteBatch.setColor(fg_color);
//do some drawing ***here's where you draw your dynamic texture***
...
spriteBatch.end();//finish write to buffer
pm = ScreenUtils.getFrameBufferPixmap(0, 0, (int) width, (int) height);//write frame buffer to Pixmap
m_fbo.end();
// pm.dispose();
// flipped.dispose();
// tx.dispose();
m_fbo.dispose();
m_fbo = null;
spriteBatch.dispose();
// return texture;
return pm;
}

Perspective correction of imageview

I'm working on an app that needs to apply perspective distortion correction to a photo taken with the phone's camera.
Once the photo is taken, the idea is to show it on an imageview and let the user mark the four corners of the document (a card, a sheet of paper, etc.) and then apply the correction based on those points.
This is an example of what im trying to achieve:
http://1.bp.blogspot.com/-ro9hniPj52E/TkoM0kTlEnI/AAAAAAAAAbQ/c2R5VrgmC_w/s640/s4.jpg
Any ideas on how to do this on android?
You don't have to use a library for this.
You can just as well use one of the drawBitmap functions of the Canvas class with a matrix that's initialized using the setPolyToPoly function of the Matrix class.
public static Bitmap cornerPin(Bitmap b, float[] srcPoints, float[] dstPoints) {
int w = b.getWidth(), h = b.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
Canvas c = new Canvas(result);
Matrix m = new Matrix();
m.setPolyToPoly(srcPoints, 0, dstPoints, 0, 4);
c.drawBitmap(b, m, p);
return result;
}
(The Paint object is only needed to enable anti-aliasing.)
Usage:
int w = bitmap.getWidth(), h = bitmap.getHeight();
float[] src = {
0, 0, // Coordinate of top left point
0, h, // Coordinate of bottom left point
w, h, // Coordinate of bottom right point
w, 0 // Coordinate of top right point
};
float[] dst = {
0, 0, // Desired coordinate of top left point
0, h, // Desired coordinate of bottom left point
w, 0.8f * h, // Desired coordinate of bottom right point
w, 0.2f * h // Desired coordinate of top right point
};
Bitmap transformed = cornerPin(bitmap, src, dst);
Where src are the coordinates of the source points, dst are the coordinates of the destination points. Result:
What you want to do goes under various names of art, "corner-pin" being the one commonly used in the visual effects industry. You need to proceed in two steps:
Compute the mapping from the the desired, rectified image, to the original, distorted, image
Actually warp the original image according to the mapping computed in (1).
The 4 (non-collinear, perspective-distorted) corners of the original image, and the 4 corners of the target (undistorted) image, define the mapping. This mapping is called a "homography" - read the pointed wikipedia page for details. Once the mapping is known, the warping at step (2) can be computed by interpolation: for every pixel in the target image, find the corresponding pixel in the original image. As this will typically not be at integer coordinates, you interpolate its color from the neighbors. Various interpolation schemes are used, the common ones being nearest-neighbor, bilinear and bicubic (in increasing order of smoothness in the results).
For Android, I'd recommend installing the OpenCV SDK , and then use the geometry transformation routines (getPerspectiveTransform and warpPerspective for the two steps above).

Filter images android?

I'm using this algorithm to filter images in andriod.
http://xjaphx.wordpress.com/2011/06/22/image-processing-convolution-matrix/
But the images are not as expected, where I can find other ways to do this. You see that applications already do this, makes it fast, this algorithm is way too slow.
regards
I recently posted there a faster version of the code you tried, you should give it a try.
By the way, what do you mean with the sentence images are not as expected ? Maybe you're just using a wrong matrix; you can find some matrix example here.
Here is the sample you requested. If you don't need to scale / offset pixel colors, you should add different implementations of convolute without those parameters and the related unnecessary computations.
class Convolution {
private static Bitmap convolute(Bitmap bmp, Matrix mat, float factor, int offset) {
/* ... */
}
private static Matrix getEdgeEnhanceMatrix() {
Matrix m = new Matrix();
m.setValues(new float[] {
0, 0, 0,
-1, 1, 0,
0, 0, 0
});
return m;
}
// the simple way
public static Bitmap edgeEnhance1(Bitmap bmp) {
return convolute(bmp, getEdgeEnhanceMatrix(), 1f, 0);
}
// if you want to apply filter to border pixels
// warning: really memory consuming
public static Bitmap edgeEnhance2(Bitmap bmp, int bgColor) {
// create a bigger canvas
Bitmap bigger = Bitmap.createBitmap(bmp.getWidth() + 2, bmp.getHeight() + 2, bmp.getConfig());
Canvas cBigger = new Canvas(bigger);
// paint background
cBigger.drawColor(bgColor);
// draw the bmp you want to manipulate from (1,1)
cBigger.drawBitmap(bmp, 1, 1, null);
// compute convolution
bigger = convolute(bigger, getEdgeEnhanceMatrix(), 1f, 0);
// create the result and project the convolution at (-1,-1)
Bitmap rt = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), bmp.getConfig());
Canvas cRt = new Canvas(rt);
cRt.drawBitmap(bigger, -1, -1, null);
return rt;
}
}
I am using this formula to filter images as per their extension
class FileExtensionFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
return (name.endsWith(".png") || name.endsWith(".PNG"));
}
If you are fetching it from the sd card let me know about this .I had code for it.

How do I create an orthographic camera that correctly scales my sprites/textures with libgdx?

I'm creating a game with libgdx that I want to run at a higher resolution on the desktop, but I want it to scale everything down correctly when I run it on android at smaller resolutions. I've read that the best way to do this is to not use a pixel perfect camera, and instead to use world coordinates, but I'm not sure how to correctly do that.
This is the code I have right now:
#Override
public void create() {
characterTexture = new Texture(Gdx.files.internal("character.png"));
characterTextureRegion = new TextureRegion(characterTexture, 0, 0, 100, 150);
batch = new SpriteBatch();
Gdx.gl10.glClearColor(0.4f, 0.6f, 0.9f, 1);
float aspectRatio = (float)Gdx.graphics.getWidth() / (float)Gdx.graphics.getHeight();
camera= new OrthographicCamera(aspectRatio, 1.0f);
}
#Override
public void render() {
GL10 gl = Gdx.graphics.getGL10();
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
camera.apply(gl);
batch.setProjectionMatrix(camera.combined);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
draw();
}
private void draw() {
//batch.getProjectionMatrix().set(camera.combined);
batch.begin();
batch.draw(characterTextureRegion, 0, 0, // the bottom left corner of the box, unrotated
1f, 1f, // the rotation center relative to the bottom left corner of the box
0.390625f, 0.5859375f, // the width and height of the box
1, 1, // the scale on the x- and y-axis
0); // the rotation angle
batch.end();
}
The texture I'm use is 256x256 with the actual image in it being 100x150.
This is the result I get when I run the game: http://i.imgur.com/HV9Bi.png
The sprite that gets rendered is massive, considering this is the original image: http://i.imgur.com/q1cZT.png
What's the best way to go about making it so that the sprites get rendered at their original size while still keeping the ability to have the game scale correctly when played in different resolutions?
I've only found two solutions, both of which I don't like.
The image showed up how it was supposed to if I used pixel coordinates for the camera, but then that didn't scale at all when I put it on my phone with a different resolution.
I can scale the texture region down when I draw it, but it seems like there is a better way because it is extremely tedious trying to figure out the correct number to scale it by.
Have you ever used the Libgdx setup tool? When you create a project with it, it has a sample image that is displayed. It seems to keep it's ratio correct no matter what size you change the screen to.
public class RotationTest implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private Texture texture;
private Sprite sprite;
Stage stage;
public boolean leonAiming = true;
#Override
public void create() {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
camera = new OrthographicCamera(1, h/w);
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("data/libgdx.png"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
TextureRegion region = new TextureRegion(texture, 0, 0, 512, 275);
sprite = new Sprite(region);
sprite.setSize(0.9f, 0.9f * sprite.getHeight() / sprite.getWidth());
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2); }....
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
sprite.draw(batch);
batch.end();
First of all you need to fix boundaries to the world (I mean to your game ). In that world only you actors(game characters) should play. If you are crossing boundaries, manage it with camera like showing up, down, left and right.

Categories

Resources