Android - Canvas Black when using Flood-Fill - android

When I implement my flood-fill class it turns my entire Bitmap black. Obviously this is not the desired effect. I've looked at the following threads:
https://stackoverflow.com/questions/24030858/flood-fill-is-coloring-my-entire-screen
Flood Fill Algorithm Resulting in Black Image
flood fill coloring on android
From what I can see I'm doing everything they've come up with in those solutions, however it hasn't led me to a solution for my problem. So to cut to the chase, here's the code with some brief explanations.
XML
I am using a relative layout and positioning (stacking) two ImageViews directly on top of each other. They both have the same image and this creates the illusion of you being able to draw on the image. However, you are in fact simply drawing on a transparent overlay.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
....
<ImageView
android:id="#+id/drawContainer2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="#id/imageMapperSurfaces"
android:contentDescription="#string/image" />
<ImageView
android:id="#+id/drawContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="#id/imageMapperSurfaces"
android:contentDescription="#string/image" />
...
</RelativeLayout>
Canvas
Then I create my Canvas with this code and I make sure to set my layer types correctly.
public void setCanvas() {
if(mFile != null && mFile.exists()) {
mPictureBitmap = BitmapFactory.decodeFile(mFile.getAbsolutePath());
mBitmap = Bitmap.createScaledBitmap(mPictureBitmap, mImageView.getWidth(), mImageView.getHeight(), false);
mPictureBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
mBitmap = mPictureBitmap.copy(Bitmap.Config.ARGB_8888, true);
mSceneBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
mBlurBitmap = blurImage(mPictureBitmap);
mCanvas = new Canvas(mBitmap);
mImageView.setImageBitmap(mBitmap);
mImageView2.setImageBitmap(mPictureBitmap);
mBlur.setImageBitmap(mBlurBitmap);
// failure to set these layer types correctly will result in a black canvas after drawing.
mImageView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mImageView2.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mImageView.bringToFront();
mAllowedToDraw = true;
setImageViewOnTouch();
}
}
Flood-Fill Implementation
I grab the color, pass my params to the flood-fill object, use the flood-fill method, return the bitmap, and finally draw the new bitmap to my canvas.
int targetColor = mSceneBitmap.getPixel((int) event.getX(), (int) event.getY());
FloodFill fill = new FloodFill(mBitmap, targetColor, Color.argb(100, 255, 0, 0));
fill.floodFill((int) event.getX(), (int) event.getY());
Bitmap bmp = fill.getImage();
mCanvas.drawBitmap(bmp, 0, 0, null);
mImageView.invalidate();
Flood-Fill Class
The boiler-plate Flood-fill algorithm.
public class FloodFill {
protected Bitmap mImage = null;
protected int[] mTolerance = new int[] { 0, 0, 0, 0 };
protected int mWidth = 0;
protected int mHeight = 0;
protected int[] mPixels = null;
protected int mFillColor = 0;
protected int[] mStartColor = new int[] { 0, 0, 0, 0 };
protected boolean[] mPixelsChecked;
protected Queue<FloodFillRange> mRanges;
public FloodFill(Bitmap img) {
copyImage(img);
}
public FloodFill(Bitmap img, int targetColor, int newColor) {
useImage(img);
setFillColor(newColor);
setTargetColor(targetColor);
}
public void setTargetColor(int targetColor) {
mStartColor[0] = Color.red(targetColor);
Log.v("Red", "" + mStartColor[0]);
mStartColor[1] = Color.green(targetColor);
Log.v("Green", "" + mStartColor[1]);
mStartColor[2] = Color.blue(targetColor);
Log.v("Blue", "" + mStartColor[2]);
mStartColor[3] = Color.alpha(targetColor);
Log.v("Alpha", "" + mStartColor[3]);
}
public int getFillColor() {
return mFillColor;
}
public void setFillColor(int value) {
mFillColor = value;
}
public int[] getTolerance() {
return mTolerance;
}
public void setTolerance(int[] value) {
mTolerance = value;
}
public void setTolerance(int value) {
mTolerance = new int[] { value, value, value, value };
}
public Bitmap getImage() {
return mImage;
}
public void copyImage(Bitmap img) {
mWidth = img.getWidth();
mHeight = img.getHeight();
mImage = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mImage);
canvas.drawBitmap(img, 0, 0, null);
mPixels = new int[mWidth * mHeight];
mImage.getPixels(mPixels, 0, mWidth, 0, 0, mWidth, mHeight);
}
public void useImage(Bitmap img) {
mWidth = img.getWidth();
mHeight = img.getHeight();
mImage = img;
mPixels = new int[mWidth * mHeight];
mImage.getPixels(mPixels, 0, mWidth, 0, 0, mWidth, mHeight);
}
protected void prepare() {
mPixelsChecked = new boolean[mPixels.length];
mRanges = new LinkedList<FloodFillRange>();
}
public void floodFill(int x, int y) {
// Setup
prepare();
if (mStartColor[0] == 0) {
// ***Get starting color.
int startPixel = mPixels[(mWidth * y) + x];
mStartColor[0] = (startPixel >> 16) & 0xff;
mStartColor[1] = (startPixel >> 8) & 0xff;
mStartColor[2] = startPixel & 0xff;
}
LinearFill(x, y);
FloodFillRange range;
while (mRanges.size() > 0) {
range = mRanges.remove();
int downPxIdx = (mWidth * (range.Y + 1)) + range.startX;
int upPxIdx = (mWidth * (range.Y - 1)) + range.startX;
int upY = range.Y - 1;
int downY = range.Y + 1;
for (int i = range.startX; i <= range.endX; i++) {
if (range.Y > 0 && (!mPixelsChecked[upPxIdx]) && CheckPixel(upPxIdx)) LinearFill(i, upY);
if (range.Y < (mHeight - 1) && (!mPixelsChecked[downPxIdx]) && CheckPixel(downPxIdx)) LinearFill(i, downY);
downPxIdx++;
upPxIdx++;
}
}
mImage.setPixels(mPixels, 0, mWidth, 0, 0, mWidth, mHeight);
}
protected void LinearFill(int x, int y) {
int lFillLoc = x;
int pxIdx = (mWidth * y) + x;
while (true) {
mPixels[pxIdx] = mFillColor;
mPixelsChecked[pxIdx] = true;
lFillLoc--;
pxIdx--;
if (lFillLoc < 0 || (mPixelsChecked[pxIdx]) || !CheckPixel(pxIdx)) {
break;
}
}
lFillLoc++;
int rFillLoc = x;
pxIdx = (mWidth * y) + x;
while (true) {
mPixels[pxIdx] = mFillColor;
mPixelsChecked[pxIdx] = true;
rFillLoc++;
pxIdx++;
if (rFillLoc >= mWidth || mPixelsChecked[pxIdx] || !CheckPixel(pxIdx)) {
break;
}
}
rFillLoc--;
FloodFillRange r = new FloodFillRange(lFillLoc, rFillLoc, y);
mRanges.offer(r);
}
protected boolean CheckPixel(int px) {
int red = (mPixels[px] >>> 16) & 0xff;
int green = (mPixels[px] >>> 8) & 0xff;
int blue = mPixels[px] & 0xff;
int alpha = (Color.alpha(mPixels[px]));
return (red >= (mStartColor[0] - mTolerance[0]) && red <= (mStartColor[0] + mTolerance[0])
&& green >= (mStartColor[1] - mTolerance[1]) && green <= (mStartColor[1] + mTolerance[1])
&& blue >= (mStartColor[2] - mTolerance[2]) && blue <= (mStartColor[2] + mTolerance[2])
&& alpha >= (mStartColor[3] - mTolerance[3]) && alpha <= (mStartColor[3] + mTolerance[3]));
}
protected class FloodFillRange {
public int startX;
public int endX;
public int Y;
public FloodFillRange(int startX, int endX, int y) {
this.startX = startX;
this.endX = endX;
this.Y = y;
}
}
}
So that's it, we should have all the pieces to the puzzle but for some reason they aren't working. I'm at a loss and any help is appreciated. Thanks!

I think you're line:
mCanvas.drawBitmap(bmp, 0, 0, null);
might need to be more like
mPaint = new Paint();
mCanvas.drawBitmap(bmp, 0, 0, mPaint);

I am not sure at everything but as far as I can tell you I would try with these solutions:
First:
instead of using decodeFile I rather use decodeInputStream
Second:
As someone has anwsered You better use a Paint() when showing the view
Third:
I am going to ask why do you need that food-fill alghorithm? I think it's too laggy and It looks a little messy to use, why dont you create a new scaled bitmap or something like an opengl effect to do it? because that is the reason why there are graphics cards;

Related

Is it possible to draw a bitmap multiple times with only 2 instances of the bitmap?

I'm trying to understand game-creation in Android. Therefore I try to program a simple TicTacToe without using buttons or layout files. Instead I want to only use bitmaps.
My Problem is that I can create the board, toggle the "X" and "O" symbol correctly, but my onDraw() only draws 2 symbols simultanously at max and I dont quite understand why or how to solve this.
public class GameScreen extends View {
List<TicTacToeSymbol> symbolList = new ArrayList<>();
float posX;
float posY;
int displayWidth;
int displayHeight;
Bitmap background;
Bitmap bitmapX;
Bitmap bitmapO;
Rect dst = new Rect();
boolean touched = false;
TicTacToeSymbol currentSymbol;
TicTacToeSymbol symbolX;
TicTacToeSymbol symbolO;
Grid grid = new Grid();
// Declaring the coordinates for the colums and rows
int ZERO_COLUMN_X = 0;
int FIRST_COLUMN_X = 480;
int SECOND_COLUMN_X = 910;
int THIRD_COLUMN_X = 1425;
(...)
int centerX = 0;
int centerY = 0;
public GameScreen(Context context) {
super(context);
try {
AssetManager assetManager = context.getAssets();
InputStream inputStream = assetManager.open("tictactoegrid.jpg");
background = BitmapFactory.decodeStream(inputStream);
inputStream = assetManager.open("X.png");
bitmapX = BitmapFactory.decodeStream(inputStream);
inputStream = assetManager.open("O.png");
bitmapO = BitmapFactory.decodeStream(inputStream);
inputStream.close();
// I create only 2 symbols, which might be the problem
symbolX = new TicTacToeSymbol(0, 0, 1);
symbolX.setBitmap(bitmapX);
symbolO = new TicTacToeSymbol(0, 0, 2);
symbolO.setBitmap(bitmapO);
setCurrentSymbol(symbolX, 1);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Display display = this.getDisplay();
Point size = new Point();
display.getSize(size);
displayWidth = size.x;
displayHeight = size.y;
}
public void toggleCurrentSymbol() {
if (currentSymbol == symbolX) {
currentSymbol = symbolO;
} else {
currentSymbol = symbolX;
}
}
public void setCurrentSymbol(TicTacToeSymbol ticTacToeSymbol, int type) {
this.currentSymbol = ticTacToeSymbol;
if (type == 1) {
currentSymbol.setType(1);
} else
currentSymbol.setType(2);
}
public void setCoordinatesCurrentSymbol(int centerX, int centerY) {
currentSymbol.setPosX(centerX);
currentSymbol.setPosY(centerY);
}
#Override
public void onDraw(Canvas canvas) {
dst.set(0, 0, displayWidth, displayHeight - 200);
canvas.drawBitmap(background, null, dst, null);
if (touched) {
// Checking where the user has clicked
// First row
if (posX >= ZERO_COLUMN_X && posX <= FIRST_COLUMN_X
&& posY > ZERO_ROW_Y && posY < FIRST_ROW_Y) {
centerX = FIRST_CENTER_X;
centerY = FIRST_CENTER_Y;
setCoordinatesCurrentSymbol(centerX, centerY);
grid.placeSignInGrid(0, 0, currentSymbol);
toggleCurrentSymbol();
}
if (posX > FIRST_COLUMN_X && posX <= SECOND_COLUMN_X
&& posY > ZERO_ROW_Y && posY < FIRST_ROW_Y) {
centerX = SECOND_CENTER_X;
centerY = FIRST_CENTER_Y;
setCoordinatesCurrentSymbol(centerX, centerY);
grid.placeSignInGrid(1, 0, currentSymbol);
toggleCurrentSymbol();
}
(...)
}
// Go through the grid, get the symbol at the position and add it to the list of symbols
for (int i = 0; i < Grid.GRID_SIZE; i++) {
for (int j = 0; j < Grid.GRID_SIZE; j++) {
if (grid.getSymbolAtField(i, j) != null) {
if (!symbolList.contains(grid.getSymbolAtField(i, j))) {
symbolList.add(grid.getSymbolAtField(i, j));
}
}
}
}
// Draw every symbol in the list.
for (TicTacToeSymbol ttts : symbolList) {
canvas.drawBitmap(ttts.getBitmap(), ttts.getPosX(), ttts.getPosY(), null);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
touched = true;
posX = event.getX();
posY = event.getY();
invalidate();
return true;
}
return false;
}
}
I create only 2 TicTacToeSymbols, namely symbolXand symbolO. Therefore the symbolList only contains these 2 and draws only those 2.
But how can I draw the same symbol several times? Else I would have to create 9 X-Symbols including the bitmap and 9 O-Symbols to cover all grid-fields with the possible symbols. This would seem wrong / not very elegant?
So how can I draw my 2 symbols several times at the correct positions?
I've looked into several posts like this but could not derive a solution for my problem:
Draw multiple times from a single bitmap on a canvas ... this positions the bitmaps randomly, but I want my symbols on specific positions.

Blur Image On touch Android

I am new to android and I want to blur image on finger touch.
I have searched some example but I found like based on seek bar value whole image get blurred.
But I want something like I can set radius of finger touch and then based on that touch, that portion of image get blurred.
MYANSWER
MainActivity1.java
here,MainActivity.java file contains bitmap that is passed from MainActivity.java .
public class MainActivity1 extends Activity implements OnClickListener {
// button
private ImageButton opacityBtn;
// custom view
private DrawingView drawView;
private Object bmpimg;
private ImageButton currPaint;
Bitmap b;
private int originalheight;
private int originalwidth;
public Bitmap tem;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main1);
Intent i1 = getIntent();
String img = i1.getStringExtra("imgpath");
Log.e("img", "" + img);
b = BitmapFactory.decodeFile(img);
// get button
opacityBtn = (ImageButton) findViewById(R.id.opacity_btn);
// listen
opacityBtn.setOnClickListener(this);
// custom view instance
// LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors);
// currPaint = (ImageButton)paintLayout.getChildAt(0);
// currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
Log.e("mainactivity1", "" + b);
// bmpimg = Bitmap.createScaledBitmap(srcimg, 100, 50, true);
// Display display = getWindowManager().getDefaultDisplay();
// Point size = new Point();
// display.getSize(size);
// int width = size.x;
// int height = size.y;
// tem=Bitmap.createScaledBitmap(b, width,
// height - 200, true);
drawView = (DrawingView) findViewById(R.id.drawing);
// fetching height and width of device
int widthPx = getWindowManager().getDefaultDisplay().getWidth();
int heightPx = getWindowManager().getDefaultDisplay().getHeight();
// set new height and width to custom class drawing view
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) drawView
.getLayoutParams();
if (b.getHeight() < heightPx && b.getWidth() < widthPx) {
params.height = b.getHeight();
params.width = b.getWidth();
} else {
if (b.getHeight() > heightPx && b.getWidth() > widthPx) {
params.height = heightPx;
params.width = widthPx;
} else if (b.getWidth() > widthPx) {
params.width = widthPx;
params.height = b.getHeight();
} else {
params.width = b.getWidth();
params.height = heightPx;
}
}
drawView.setLayoutParams(params);
drawView.setCanvasBitmap(b, b.getHeight(),
b.getWidth(), widthPx, heightPx);
if(b.getHeight()<heightPx&&b.getWidth()<widthPx){
this.originalheight=b.getHeight();
this.originalwidth=b.getWidth();
}else{
if(b.getHeight()>heightPx&&b.getWidth()>widthPx){
this.originalheight=heightPx;
this.originalwidth=widthPx;
}
else if(b.getWidth()>widthPx){
this.originalwidth=widthPx;
this.originalheight=b.getHeight();
}
else{
this.originalwidth=b.getWidth();
this.originalheight=heightPx;
}
}
tem=Bitmap.createScaledBitmap(b, originalwidth,
originalheight, true);
Bitmap bitmap=createBitmap_ScriptIntrinsicBlur(tem,40);
drawView.firstsetupdrawing(bitmap);
// drawView.setScree_w(width);
// drawView.setScreen_h(height);
}
/*
* #Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the
* menu; this adds items to the action bar if it is present.
* getMenuInflater().inflate(R.menu.main, menu); return true; }
*/
/* public void paintClicked(View view) {
//use chosen color
//set erase false
// drawView.setErase(false);
// drawView.setPaintAlpha(100);
// drawView.setBrushSize(drawView.getLastBrushSize());
if(view!=currPaint){
Bitmap bitmap=createBitmap_ScriptIntrinsicBlur(tem,40);
drawView.firstsetupdrawing(bitmap);
// ImageButton imgView = (ImageButton)view;
// String color = view.getTag().toString();
// drawView.setColor(color);
// //update ui
// imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
// currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint));
// currPaint=(ImageButton)view;
}
}
*/
#Override
public void onClick(View view) {
if (view.getId() == R.id.opacity_btn) {
// launch opacity chooser
final Dialog seekDialog = new Dialog(this);
seekDialog.setTitle("Opacity level:");
seekDialog.setContentView(R.layout.opacity_chooser);
// get ui elements
final TextView seekTxt = (TextView) seekDialog
.findViewById(R.id.opq_txt);
final SeekBar seekOpq = (SeekBar) seekDialog
.findViewById(R.id.opacity_seek);
// set max
seekOpq.setMax(40);
// show current level
int currLevel = drawView.getPaintAlpha();
seekTxt.setText(currLevel + "%");
seekOpq.setProgress(currLevel);
// update as user interacts
seekOpq.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
seekTxt.setText(Integer.toString(progress) + "%");
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
// listen for clicks on ok
Button opqBtn = (Button) seekDialog.findViewById(R.id.opq_ok);
opqBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Bitmap bitmap=createBitmap_ScriptIntrinsicBlur(tem, seekOpq.getProgress());
drawView.setPaintAlpha(seekOpq.getProgress(),bitmap);
seekDialog.dismiss();
}
});
// show dialog
seekDialog.show();
}
}
public Bitmap createBitmap_ScriptIntrinsicBlur(Bitmap src, int radius) {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
// Radius range (0 < r <= 25)
/* if (r <= 1) {
r = 1;
} else if (r > 25) {
r = 25;
}
Bitmap bitmap = Bitmap.createBitmap(src.getWidth(), src.getHeight(),
Bitmap.Config.ARGB_8888);
RenderScript renderScript = RenderScript.create(this);
Allocation blurInput = Allocation.createFromBitmap(renderScript, src);
Allocation blurOutput = Allocation.createFromBitmap(renderScript,
bitmap);
ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(renderScript,
Element.U8_4(renderScript));
blur.setInput(blurInput);
blur.setRadius(r);
blur.forEach(blurOutput);
blurOutput.copyTo(bitmap);
renderScript.destroy();
return bitmap;*/
//here i can make radius up to 40 use for it below code
int w = src.getWidth();
int h = src.getHeight();
int[] pix = new int[w * h];
src.getPixels(pix, 0, w, 0, 0, w, h);
for(int r = radius; r >= 1; r /= 2)
{
for(int i = r; i < h - r; i++)
{
for(int j = r; j < w - r; j++)
{
int tl = pix[(i - r) * w + j - r];
int tr = pix[(i - r) * w + j + r];
int tc = pix[(i - r) * w + j];
int bl = pix[(i + r) * w + j - r];
int br = pix[(i + r) * w + j + r];
int bc = pix[(i + r) * w + j];
int cl = pix[i * w + j - r];
int cr = pix[i * w + j + r];
pix[(i * w) + j] = 0xFF000000 |
(((tl & 0xFF) + (tr & 0xFF) + (tc & 0xFF) + (bl & 0xFF) +
(br & 0xFF) + (bc & 0xFF) + (cl & 0xFF) + (cr & 0xFF)) >> 3) & 0xFF |
(((tl & 0xFF00) + (tr & 0xFF00) + (tc & 0xFF00) + (bl & 0xFF00)
+ (br & 0xFF00) + (bc & 0xFF00) + (cl & 0xFF00) + (cr & 0xFF00)) >> 3) & 0xFF00 |
(((tl & 0xFF0000) + (tr & 0xFF0000) + (tc & 0xFF0000) +
(bl & 0xFF0000) + (br & 0xFF0000) + (bc & 0xFF0000) + (cl & 0xFF0000) +
(cr & 0xFF0000)) >> 3) & 0xFF0000;
}
}
}
Bitmap blurred = Bitmap.createBitmap(w, h, src.getConfig());
blurred.setPixels(pix, 0, w, 0, 0, w, h);
return blurred;
}
}
DrawingView.java
Here,DrawingView.java contains canavas so we canput image on canvas and blur it.
public class DrawingView extends View {
// drawing path
private Path drawPath;
// drawing and canvas paint
private Paint drawPaint, canvasPaint;
// initial color
private int paintColor = 0xFFC0C0C0, paintAlpha = 255;
// canvas
private Canvas drawCanvas;
// canvas bitmap
private Bitmap canvasBitmap;
int originalheight,originalwidth;
/**
* #return the scree_w
*/
private BlurMaskFilter blurMaskFilter;
public int scree_w, screen_h;
public void setCanvasBitmap(Bitmap bitmap1, int i, int j, int widthPx, int heightPx) {
this.canvasBitmap = bitmap1;
if(i<heightPx&&j<widthPx){
this.originalheight=i;
this.originalwidth=j;
}else{
if(i>heightPx&&j>widthPx){
this.originalheight=heightPx-1;
this.originalwidth=widthPx-1;
}
else if(j>widthPx){
this.originalwidth=widthPx-1;
this.originalheight=i;
}
else{
this.originalwidth=j;
this.originalheight=heightPx-1;
}
}
}
public void setScree_w(int width) {
// TODO Auto-generated method stub
this.scree_w = width;
}
public void setScreen_h(int height) {
// TODO Auto-generated method stub
this.screen_h = height;
}
// constructor
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
// prepare drawing
private void setupDrawing() {
drawPath = new Path();
drawPaint = new Paint();
//
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(30);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint();
// BitmapShader patternBMPshader = new BitmapShader(canvasBitmap,
// Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// //color and shader
// drawPaint.setColor(0xFFFFFFFF);
// drawPaint.setShader(patternBMPshader);
blurMaskFilter = new BlurMaskFilter( 5,
BlurMaskFilter.Blur.NORMAL);
drawPaint.setMaskFilter(blurMaskFilter);
}
public void firstsetupdrawing( Bitmap bitmap){
drawPath = new Path();
drawPaint = new Paint();
//
// drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(30);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint();
// BitmapShader patternBMPshader = new BitmapShader(canvasBitmap,
// Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// //color and shader
// drawPaint.setColor(0xFFFFFFFF);
// drawPaint.setShader(patternBMPshader);
blurMaskFilter = new BlurMaskFilter( 5,
BlurMaskFilter.Blur.NORMAL);
drawPaint.setMaskFilter(blurMaskFilter);
drawPaint.setColor(paintColor);
// drawPaint.setAlpha(paintAlpha);
BitmapShader patternBMPshader = new BitmapShader(bitmap,
Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//color and shader
drawPaint.setColor(0xFFFFFFFF);
drawPaint.setShader(patternBMPshader);
}
// view assigned size
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// int i=canvasBitmap.getHeight();
// int y=canvasBitmap.getWidth();
Log.e("hiyt wid-------------------------", "" + scree_w
+ "dsgvdfg sunita u will be happy" + screen_h);
canvasBitmap = Bitmap.createScaledBitmap(canvasBitmap,originalwidth+1,originalheight+1, true);
drawCanvas = new Canvas(canvasBitmap);
}
// draw view
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
// respond to touch interaction
float x = 0, y = 0;
public boolean onTouchEvent(MotionEvent event) {
Log.e("getalph drawing view", "" + getPaintAlpha());
float touchX = 0, touchY = 0;
x = touchX;
y = touchY;
touchX = event.getX();
touchY = event.getY();
// respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
/*
* if (x == touchX && y == touchY) {
*
* drawPath.moveTo(touchX + 1, touchY + 1); } else {
*/
drawPath.moveTo(touchX, touchY);
// }
break;
case MotionEvent.ACTION_MOVE:
/*
* if (x == touchX && y == touchY) {
*
* drawPath.lineTo(touchX + 1, touchY + 1);
*
* } else {
*/
drawPath.lineTo(touchX, touchY);
// }
break;
case MotionEvent.ACTION_UP:
/*
* if (x == touchX && y == touchY) {
*
* drawPath.lineTo(touchX + 1, touchY + 1);
* drawCanvas.drawPath(drawPath, drawPaint); drawPath.reset(); }
*
* else {
*/
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
// }
break;
default:
return false;
}
// redraw
invalidate();
return true;
}
// return current alpha
public int getPaintAlpha() {
return Math.round((float) paintAlpha / 255 * 40);
}
// set alpha
public void setPaintAlpha(int newAlpha, Bitmap bitmap) {
paintAlpha = Math.round((float) newAlpha / 40 * 255);
drawPaint.setColor(paintColor);
drawPaint.setAlpha(paintAlpha);
BitmapShader patternBMPshader = new BitmapShader(bitmap,
Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//color and shader
drawPaint.setColor(0xFFFFFFFF);
drawPaint.setShader(patternBMPshader);
}
public void setColor(String newColor) {
invalidate();
//check whether color value or pattern name
if(newColor.startsWith("#")){
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
drawPaint.setShader(null);
}
else{
//pattern
int patternID = getResources().getIdentifier(
newColor, "drawable", "com.example.drawingfun");
//decode
// Bitmap patternBMP = BitmapFactory.decodeResource(getResources(), patternID);
Bitmap patternBMP = BitmapFactory.decodeResource(getResources(),R.drawable.sun);
//create shader
Log.e("drawing view pattern+getalpha", "" + patternBMP+"dsfsdsd"+getPaintAlpha());
BitmapShader patternBMPshader = new BitmapShader(patternBMP,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
//color and shader
drawPaint.setColor(0xFFFFFFFF);
drawPaint.setShader(patternBMPshader);
}
}
}

How to set-up automatic collision with just an update() function?

I've just started with Android programming using eclipse and recently came across this problem. I have a bunch of sprites assigned to an arraylist. Now, I want to make it so that collision is detected automatically between sprites but the template I'm currently using can only detect collision between the surface's borders and the moving sprites. Each sprite's position and speed is generated randomly.
How can I change the update() function in my Sprite() class to detect collision between the moving sprites themselves and at the same changing/bouncing to the opposite direction?
Here's my Sprite class template:
package com.gameproject.cai_test;
import java.util.Random;
public Sprite(GameView gameView, Bitmap bmp) {
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
this.gameView = gameView;
this.bmp = bmp;
Random rnd = new Random();
x = rnd.nextInt(gameView.getWidth() - width);
y = rnd.nextInt(gameView.getHeight() - height);
xSpeed = rnd.nextInt(MAX_SPEED * 2) - MAX_SPEED;
ySpeed = rnd.nextInt(MAX_SPEED * 2) - MAX_SPEED;
}
private void update() {
if (x >= gameView.getWidth() - width - xSpeed || x + xSpeed <= 0) {
xSpeed = -xSpeed;
}
x = x + xSpeed;
if (y >= gameView.getHeight() - height - ySpeed || y + ySpeed <= 0) {
ySpeed = -ySpeed;
}
y = y + ySpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
}
public void onDraw(Canvas canvas) {
update();
int srcX = currentFrame * width;
int srcY = getAnimationRow() * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
private int getAnimationRow() {
double dirDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2) + 2);
int direction = (int) Math.round(dirDouble) % BMP_ROWS;
return DIRECTION_TO_ANIMATION_MAP[direction];
}
//gameplay operations
//only values from 0 to 9 will be picked; each assigned its own sprite in the list
public int randomValue(){
Random rnd = new Random();
RandomValue = rnd.nextInt(10);
return RandomValue;
}
//sequence operation from addition, subtraction, multiplication, and division
public int produceSum(){
int addOne = 0;
int addTwo = 0;
Sum = addOne + addTwo;
return Sum;
}
public int produceDiff(){
int deductOne = 0;
int deductTwo = 0;
Difference = deductOne - deductTwo;
return Difference;
}
public int produceProduct(){
int multiOne = 0;
int multiTwo = 0;
Product = multiOne * multiTwo;
return Product;
}
public int produceQuotient(){
int divideOne = 0;
int divideTwo = 0;
Quotient = divideOne / divideTwo;
return Quotient;
}
//each time this returns true, the game is reset with new operation
//compares the value of the bubble picked to the random number being compared through operations
public boolean compareBubbleValue(int randomBubble, int bubbleValue){
if (randomBubble == bubbleValue){
return true;
}
return false;
}
}
As you can see, the update() method only checks the collision between the moving sprites and the borders.
Okey, so lets name your array of sprites spriteArray and loop through it twice
public Rect getBounds(){ //put this in your sprite and enemy-class.
return new Rect(x, y, x+width, y+height);
}
Public void checkCollision(){
for (int i = 0; i<spriteArray.size(); i++){
Rect mySprite = spriteArray.get(i).getBounds(); //create rect for every sprite in array
for (int j = 0; j<spriteArray.size(); i++){
Rect myOtherSprite = spriteArray.get(i).getBounds();
if(mySprite.intersect(myOtherSprite)){ //check if they touch
//Todo code here
}
}
}
}
then you just put this method in your update-method.
Here's the coding for the GameView class (pardon the mess, it's a jumble of codes and comments):
package com.gameproject.cai_test;
public class GameView extends SurfaceView {
private Bitmap bmp;
private Bitmap background;
private Bitmap backgroundImage;
private Bitmap pop;
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private List<Sprite> sprites = new ArrayList<Sprite>();
private List<TempSprite> temps = new ArrayList<TempSprite>();
private int[] bubbleValue = {0,1,2,3,4,5,6,7,8,9,10};
private long lastClick;
private SpriteObject timer;
private SpriteObject morebanner;
private SpriteObject formulaBox;
private SpriteObject levelbanner1;
private SurfaceHolder surfaceHolder;
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
timer = new SpriteObject (BitmapFactory.decodeResource(getResources(), R.drawable.hourglass), 1200, 100);
morebanner = new SpriteObject(BitmapFactory.decodeResource(getResources(), R.drawable.morebanner), 650, 300);
formulaBox = new SpriteObject(BitmapFactory.decodeResource(getResources(), R.drawable.formulabox), 650, 600);
background = BitmapFactory.decodeResource(getResources(), R.drawable.background);
backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.background);
pop = BitmapFactory.decodeResource(getResources(), R.drawable.pop);
final Toast toast1 = Toast.makeText(context, "LEVEL 1 start", Toast.LENGTH_LONG);
holder = getHolder();
holder.addCallback(new Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
//setSurfaceSize(getWidth(), getHeight());
toast1.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast1.show();
createSprites();
gameLoopThread.setRunning(true);
gameLoopThread.start();
//banner();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
private void createSprites() {
sprites.add(createSprite(R.drawable.bubble1));
sprites.add(createSprite(R.drawable.bubble2));
sprites.add(createSprite(R.drawable.bubble3));
sprites.add(createSprite(R.drawable.bubble4));
sprites.add(createSprite(R.drawable.bubble5));
sprites.add(createSprite(R.drawable.bubble6));
sprites.add(createSprite(R.drawable.bubble7));
sprites.add(createSprite(R.drawable.bubble8));
sprites.add(createSprite(R.drawable.bubble9));
sprites.add(createSprite(R.drawable.bubble10));
for (int i = 0; i <= 10; i++){
bubbleValue[i] = sprites.indexOf(i);
}
}
private Sprite createSprite(int resource) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resource);
return new Sprite(this, bmp);
}
public void setSurfaceSize(int width, int height)
{
synchronized (surfaceHolder)
{
int canvasWidth = width;
int canvasHeight = height;
backgroundImage = Bitmap.createScaledBitmap(backgroundImage, width, height, true);
}
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
//levelbanner1.draw(canvas);//causes error when applied;for reference only
for (int i = temps.size() - 1; i >= 0; i--) {
temps.get(i).onDraw(canvas);
}
for (Sprite sprite : sprites) {
timer.draw(canvas);
//formulaBox.draw(canvas);
sprite.onDraw(canvas);
}
if (sprites.size() == 0){
morebanner.draw(canvas);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick > 300) {
lastClick = System.currentTimeMillis();
float x = event.getX();
float y = event.getY();
synchronized (getHolder()) {
for (int i = sprites.size() - 1; i >= 0; i--) {
Sprite sprite = sprites.get(i);
if (sprite.isCollition(x, y)) {
sprites.remove(sprite);
temps.add(new TempSprite(temps, this, x, y, pop));
break;
}
}
}
}
return true;
}
public void update(){
//for possible check of collision bet. sprites
//
}
}
I've tried assigning a Rect for the sprites here and checking collision on the bottom update() function but result gets awry and produces a runtime error. Probably would be better if its automated in the Sprite class update() function, just as it does for border collision.
If you want to have nice and proper collisions between your sprites, maybe looking at a physics engine like http://www.jbox2d.org/ would help.
It will handle a lot of the complex specific cases for you (tunnelling, time of impact, broadphase for early discard...)

Android: Highlight effect on image programatically

Is there any way to highlight tab icon image programmatically without using separate drawable resource?
I tried using PorterDuffColorFilter but it doesn't look good:
// apply a color mask to the icon to mark it as selected
int selectedIconMaskColor = view.getResources().getColor(R.color.tab_icon_selected);
PorterDuffColorFilter selectedIconFilter = new PorterDuffColorFilter(selectedIconMaskColor,
PorterDuff.Mode.SRC_ATOP);
copyIconDrawable.setColorFilter(selectedIconFilter);
Are there any other alternatives?
I ended up using simple image manipulation class:
import android.graphics.Bitmap;
import android.graphics.Color;
/**
* Image with support for filtering.
*/
public class FilteredImage {
private Bitmap image;
private int width;
private int height;
private int[] colorArray;
/**
* Constructor.
*
* #param img the original image
*/
public FilteredImage(Bitmap img) {
this.image = img;
width = img.getWidth();
height = img.getHeight();
colorArray = new int[width * height];
image.getPixels(colorArray, 0, width, 0, 0, width, height);
applyHighlightFilter();
}
/**
* Get the color for a specified pixel.
*
* #param x x
* #param y y
* #return color
*/
public int getPixelColor(int x, int y) {
return colorArray[y * width + x];
}
/**
* Gets the image.
*
* #return Returns the image.
*/
public Bitmap getImage() {
return image;
}
/**
* Applies green highlight filter to the image.
*/
private void applyHighlightFilter() {
int a;
int r;
int g;
int b;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int c = getPixelColor(x, y);
a = Color.alpha(c);
r = Color.red(c);
g = Color.green(c);
b = Color.blue(c);
r = (int) (r * 0.8);
g = (int) (g * 1.6);
b = (int) (b * 0.8);
if (r > 255) {
r = 255;
}
if (r < 0) {
r = 0;
}
if (g > 255) {
g = 255;
}
if (g < 0) {
g = 0;
}
if (b > 255) {
b = 255;
}
if (b < 0) {
b = 0;
}
int resultColor = Color.argb(a, r, g, b);
image.setPixel(x, y, resultColor);
}
}
}
}
I came across this code which works perfectly and performs faster. Hope this'll help future readers.
public static Bitmap highlightImage(Bitmap src) {
// create new bitmap, which will be painted and becomes result image
Bitmap bmOut = Bitmap.createBitmap(src.getWidth() + 96, src.getHeight() + 96, Bitmap.Config.ARGB_8888);
// setup canvas for painting
Canvas canvas = new Canvas(bmOut);
// setup default color
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
// create a blur paint for capturing alpha
Paint ptBlur = new Paint();
ptBlur.setMaskFilter(new BlurMaskFilter(15, BlurMaskFilter.Blur.NORMAL));
int[] offsetXY = new int[2];
// capture alpha into a bitmap
Bitmap bmAlpha = src.extractAlpha(ptBlur, offsetXY);
// create a color paint
Paint ptAlphaColor = new Paint();
ptAlphaColor.setColor(0xFFFFFFFF);
// paint color for captured alpha region (bitmap)
canvas.drawBitmap(bmAlpha, offsetXY[0], offsetXY[1], ptAlphaColor);
// free memory
bmAlpha.recycle();
// paint the image source
canvas.drawBitmap(src, 0, 0, null);
// return out final image
return bmOut;
}
I did this, not best solution but works...
imageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
imageView.setColorFilter(R.color.button_selection);
doLater(SECOND / 3, new Run() {
#Override
public void run() {
imageView.setColorFilter(0x00000000);
}
});
doClick(imageView);
}
});
And this is for some other view...
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
view.getBackground().setColorFilter(R.color.button_selection, Mode.SRC_OVER);
view.getBackground().invalidateSelf();
doLater(SECOND / 3, new Run() {
#Override
public void run() {
view.getBackground().setColorFilter(0x00000000, Mode.SRC_OVER);
view.getBackground().invalidateSelf();
}
});
doClick(view);
}
});

Android Bitmap is black

I'm trying to draw a map from a textfile onto a Bitmap, but the Bitmap is all black
First i load a textfile that looks like this (shortened):
0000000000 (200 width)
0111111110
0111100010
0000111110
0000111000
0000000000
(120 height)
Where "1" is ground and "0" is a wall, 1 should be white and 0 should be black.
Code:
public Map(String map) {
this.map = map;
init();
}
public void init() {
mapArray = new int[WIDTH*HEIGHT];
String[] splitMap = map.split("\n");
int width = splitMap[0].length();
int height = splitMap.length;
int[] colors = new int[WIDTH * HEIGHT];
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
int type = Integer.valueOf(splitMap[y].charAt(x));
setType(x, y, type);
if(type == WALL) {
setColor(x, y, Color.rgb(0, 0, 0), colors);
} else if(type == GROUND) {
setColor(x, y, Color.rgb(255, 255, 255), colors);
} else if(type == GOAL) {
setColor(x, y, Color.rgb(255, 255, 255), colors);
}
}
}
bitmap = Bitmap.createBitmap(colors, WIDTH, HEIGHT, Config.ARGB_8888);
}
public void setColor(int x, int y, int color, int[] colors) {
for(int y1 = 0; y1 < 4; y1++) {
for(int x1 = 0; x1 < 4; x1++) {
colors[(x + x1) + (y + y1) * WIDTH] = color;
}
}
}
public void setPixel(int x, int y, int color) {
for(int y1 = 0; y1 < 4; y1++) {
for(int x1 = 0; x1 < 4; x1++) {
bitmap.setPixel(x + x1, y + y1, color);
}
}
}
public void setType(int x, int y, int type) {
for(int y1 = 0; y1 < 4; y1++) {
for(int x1 = 0; x1 < 4; x1++) {
mapArray[(x + x1) + (y + y1) * WIDTH] = type;
}
}
}
public int getType(int x, int y) {
return mapArray[x + y * WIDTH];
}
public void doDraw(Canvas canvas) {
canvas.drawBitmap(bitmap, 0, 0, null);
}
private final static int WALL = 0;
private final static int GROUND = 1;
private final static int GOAL = 2;
private final static int WIDTH = 800;
private final static int HEIGHT = 480;
private int[] mapArray = null;
private String map = null;
public Bitmap bitmap;
int type = Integer.valueOf(splitMap[y].charAt(x));
That's the line that's causing the problem.
scala> Integer.valueOf('1')
res3: java.lang.Integer = 49
scala> Integer.valueOf('0')
res4: java.lang.Integer = 48
The problem is that charAt gives you a char, which you then convert into an integer. What you really want to do is Integer.parseInt(splitMap[y].substring(x,x+1)
Integer.valueOf("0".substring(0,1))
res7: java.lang.Integer = 0
This illustrates a lesson though - never leave a switch statement without providing a default; similarly never leave an if/else if/... without leaving an else. Even if you're expecting never to hit it, you should put some noticeable error message if you do; it will help you debug.

Categories

Resources