Quando si implementa la classe flood-fill
, il mio intero Bitmap
diventa nero. Ovviamente questo non è l'effetto desiderato. Ho guardato i seguenti thread:Android - Tela nera quando si utilizza Flood-Fill
- https://stackoverflow.com/questions/24030858/flood-fill-is-coloring-my-entire-screen
- Flood Fill Algorithm Resulting in Black Image
- flood fill coloring on android
Da quello che posso vedere che sto facendo tutto quello che è venuta in mente a quelle soluzioni, tuttavia non mi ha portato a una soluzione per il mio problema. Quindi, per andare al sodo, ecco il codice con alcune brevi spiegazioni.
XML
sto usando un layout relativa e posizionamento (impilabile) due ImageViews
direttamente sopra l'altro. Entrambi hanno la stessa immagine e questo crea l'illusione di essere in grado di disegnare sull'immagine. Tuttavia, stai semplicemente disegnando su una sovrapposizione trasparente.
<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>
Tela
Poi Creo il mio Canvas
con questo codice e faccio in modo di impostare correttamente i miei tipi di livello.
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 Attuazione
Afferro il colore, passare i miei params all'oggetto flood-fill
, utilizzare il metodo flood-fill
, restituire il bitmap
, e infine disegnare la nuova bitmap
alla mia 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 Classe
La caldaia-piastra Flood-fill
algoritmo.
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;
}
}
}
Quindi è tutto, dovremmo avere tutti i pezzi del puzzle ma per qualche motivo non stanno funzionando. Sono in perdita e ogni aiuto è apprezzato. Grazie!