I'm trying to implement zoom feature in my coloring book app, the zoom working perfectly but I have 3 main problems in canvas after zoom:
- Drag/scroll the canvas is not smooth and difficult after zoom.
- I can't detect the pinch motion in order to avoid coloring during zoom process.
- After zoom it is not filling the exact tapped point so I would like to keep filling the tapped point.
Here is my code:
public class MainActivity extends AppCompatActivity implements View.OnTouchListener, View.OnClickListener { private static final int PERMISSION_REQUEST_CODE = 1; public static ArrayList<Point> drawnPoints = new ArrayList<Point>(); Paint paint; ImageView iv; int position, code; Button White, Black, Gray, lightOrange, Brown, Yellow, deepBlue, lightBlue, deepPurple, lightPurple, deepGreen, lightGreen, deepPink, lightPink, Red, deepOrange; int h, w; Drawable drawable; private RelativeLayout drawingLayout; private MyView myView; private ArrayList<Path> paths = new ArrayList<Path>(); private InterstitialAd mInterstitialAd; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getSupportActionBar().setDisplayHomeAsUpEnabled(true); NativeExpressAdView adView = (NativeExpressAdView) findViewById(R.id.adView); AdRequest request = new AdRequest.Builder().build(); adView.loadAd(request); mInterstitialAd = new InterstitialAd(this); mInterstitialAd.setAdUnitId(getString(R.string.interstitial_unit_id)); requestNewInterstitial(); mInterstitialAd.setAdListener(new AdListener() { @Override public void onAdLoaded() { if (mInterstitialAd.isLoaded()) { mInterstitialAd.show(); } } }); iv = (ImageView) findViewById(R.id.coringImage); Bundle extras = getIntent().getExtras(); if (extras != null) { // code of category //position of image in the category array position = extras.getInt("position"); code = extras.getInt("code"); } drawingLayout = (RelativeLayout) findViewById(R.id.relative_layout); White = (Button) findViewById(R.id.white); Black = (Button) findViewById(R.id.black); Gray = (Button) findViewById(R.id.gray); lightOrange = (Button) findViewById(R.id.light_orange); Brown = (Button) findViewById(R.id.brown); Yellow = (Button) findViewById(R.id.yellow); deepBlue = (Button) findViewById(R.id.deep_blue); lightBlue = (Button) findViewById(R.id.light_blue); deepPurple = (Button) findViewById(R.id.deep_purple); lightPurple = (Button) findViewById(R.id.light_purple); deepGreen = (Button) findViewById(R.id.deep_green); lightGreen = (Button) findViewById(R.id.light_green); deepPink = (Button) findViewById(R.id.deep_pink); lightPink = (Button) findViewById(R.id.light_pink); Red = (Button) findViewById(R.id.red); deepOrange = (Button) findViewById(R.id.deep_orange); White.setOnClickListener(this); Black.setOnClickListener(this); Gray.setOnClickListener(this); lightOrange.setOnClickListener(this); Brown.setOnClickListener(this); Yellow.setOnClickListener(this); deepBlue.setOnClickListener(this); lightBlue.setOnClickListener(this); deepPurple.setOnClickListener(this); lightPurple.setOnClickListener(this); deepGreen.setOnClickListener(this); lightGreen.setOnClickListener(this); deepPink.setOnClickListener(this); lightPink.setOnClickListener(this); Red.setOnClickListener(this); deepOrange.setOnClickListener(this); myView = new MyView(this); drawingLayout.addView(myView); } @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub return false; } //MeunItems @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.share_save_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_share: onShareImageItem(); break; case R.id.action_save: if (Build.VERSION.SDK_INT >= 23) { if (checkPermission()) { save(myView); } else { requestPermission(); // Code for permission } } else { // Code for Below 23 API Oriented Device save(myView); } break; case android.R.id.home: this.finish(); break; } return super.onOptionsItemSelected(item); } //Share the Image public void onShareImageItem() { String package_name = getPackageName(); // Get access to the URI for the bitmap Uri bmpUri = getLocalBitmapUri(iv); if (bmpUri != null) { // Construct a ShareIntent with link to image Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, bmpUri); shareIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.app_name) + "\n" + "https://play.google.com/store/apps/details?id=" + package_name); shareIntent.setType("image/*"); startActivity(Intent.createChooser(shareIntent, getString(R.string.action_share))); } else { } } // Returns the URI path to the Bitmap displayed in specified ImageView public Uri getLocalBitmapUri(ImageView iv) { iv.setImageBitmap(myView.scaledBitmap); // Extract Bitmap from ImageView drawable drawable = iv.getDrawable(); Bitmap bmp = null; if (drawable instanceof BitmapDrawable) { bmp = ((BitmapDrawable) iv.getDrawable()).getBitmap(); } else { return null; } // Store image to default external storage directory Uri bmpUri = null; try { File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png"); FileOutputStream out = new FileOutputStream(file); bmp.compress(Bitmap.CompressFormat.PNG, 90, out); out.close(); bmpUri = Uri.fromFile(file); } catch (IOException e) { e.printStackTrace(); } return bmpUri; } public void save(View view) { File filename; iv.setImageBitmap(myView.scaledBitmap); try { File filepath = Environment.getExternalStorageDirectory(); File dir = new File(filepath.getAbsolutePath() + "/" + getString(R.string.app_name) + "/"); dir.mkdirs(); String fileName = "/" + System.currentTimeMillis() + "image.jpg"; ; filename = new File(dir, fileName); FileOutputStream fos = new FileOutputStream(filename); myView.scaledBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); Toast.makeText(getApplicationContext(), getString(R.string.save), Toast.LENGTH_LONG).show(); MediaScannerConnection.scanFile(MainActivity.this, new String[]{filename.toString()}, null, new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { Log.i("ExternalStorage", "Scanned " + path + ":"); Log.i("ExternalStorage", "-> uri=" + uri); } }); } catch (Exception e) { e.printStackTrace(); } } @Override public void onClick(View view) { enable(); switch (view.getId()) { case R.id.white: paint.setColor(getResources().getColor(R.color.white)); White.setSelected(true); break; case R.id.black: paint.setColor(getResources().getColor(R.color.black)); Black.setSelected(true); break; case R.id.gray: paint.setColor(getResources().getColor(R.color.gray)); Gray.setSelected(true); break; case R.id.light_orange: paint.setColor(getResources().getColor(R.color.light_orange)); lightOrange.setSelected(true); break; case R.id.brown: paint.setColor(getResources().getColor(R.color.brown)); Brown.setSelected(true); break; case R.id.yellow: paint.setColor(getResources().getColor(R.color.yellow)); Yellow.setSelected(true); break; case R.id.deep_blue: paint.setColor(getResources().getColor(R.color.deep_blue)); deepBlue.setSelected(true); break; case R.id.light_blue: paint.setColor(getResources().getColor(R.color.light_blue)); lightBlue.setSelected(true); break; case R.id.deep_purple: paint.setColor(getResources().getColor(R.color.deep_purple)); deepPurple.setSelected(true); break; case R.id.light_purple: paint.setColor(getResources().getColor(R.color.light_purple)); lightPurple.setSelected(true); break; case R.id.deep_green: paint.setColor(getResources().getColor(R.color.deep_green)); deepGreen.setSelected(true); break; case R.id.light_green: paint.setColor(getResources().getColor(R.color.light_green)); lightGreen.setSelected(true); break; case R.id.deep_pink: paint.setColor(getResources().getColor(R.color.deep_pink)); deepPink.setSelected(true); break; case R.id.light_pink: paint.setColor(getResources().getColor(R.color.light_pink)); lightPink.setSelected(true); break; case R.id.red: paint.setColor(getResources().getColor(R.color.red)); Red.setSelected(true); break; case R.id.deep_orange: paint.setColor(getResources().getColor(R.color.deep_orange)); deepOrange.setSelected(true); break; } } public void enable() { White.setSelected(false); Gray.setSelected(false); Black.setSelected(false); lightOrange.setSelected(false); Brown.setSelected(false); Yellow.setSelected(false); deepBlue.setSelected(false); lightBlue.setSelected(false); deepPurple.setSelected(false); lightPurple.setSelected(false); deepGreen.setSelected(false); lightGreen.setSelected(false); deepPink.setSelected(false); lightPink.setSelected(false); Red.setSelected(false); deepOrange.setSelected(false); } private boolean checkPermission() { int result = ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE); if (result == PackageManager.PERMISSION_GRANTED) { return true; } else { return false; } } private void requestPermission() { if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) { Toast.makeText(MainActivity.this, getString(R.string.permission), Toast.LENGTH_LONG).show(); } else { ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE); } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case PERMISSION_REQUEST_CODE: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.e("value", "Permission Granted, Now you can use local drive ."); } else { Log.e("value", "Permission Denied, You cannot use local drive ."); } break; } } private void requestNewInterstitial() { AdRequest adRequest = new AdRequest.Builder().build(); mInterstitialAd.loadAd(adRequest); } // flood fill public class MyView extends View { Point p1 = new Point(); Bitmap mBitmap, scaledBitmap; ProgressDialog pd; Canvas canvas; private Path path; //Test 20/8/2017// private ScaleGestureDetector scaleDetector; private float scaleFactor = 1.f; ////////////////// public MyView(Context context) { super(context); //Test 20/8/2017// init(context); ////////////////// this.path = new Path(); paint = new Paint(); paint.setAntiAlias(true); pd = new ProgressDialog(context); paint.setStyle(Paint.Style.STROKE); paint.setStrokeJoin(Paint.Join.ROUND); paint.setStrokeWidth(5f); int id = getResources().getIdentifier("gp" + code + "_" + position, "drawable", getPackageName()); mBitmap = BitmapFactory.decodeResource(getResources(), id).copy(Bitmap.Config.ARGB_8888, true); // Get the screen dimension DisplayMetrics displaymetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displaymetrics); Display getOrient = getWindowManager().getDefaultDisplay(); int orientation = Configuration.ORIENTATION_UNDEFINED; if (getOrient.getWidth() == getOrient.getHeight()) { orientation = Configuration.ORIENTATION_SQUARE; } else { if (getOrient.getWidth() < getOrient.getHeight()) { orientation = Configuration.ORIENTATION_PORTRAIT; } else { orientation = Configuration.ORIENTATION_LANDSCAPE; } } if (orientation == Configuration.ORIENTATION_PORTRAIT) { h = displaymetrics.heightPixels / 2 + 100; w = displaymetrics.widthPixels; } if (orientation == Configuration.ORIENTATION_LANDSCAPE) { //for mdpi screen 760×1024 tablet Display display = getWindowManager().getDefaultDisplay(); float density = context.getResources().getDisplayMetrics().density; if (density >= 1.0 && display.getWidth() == 1024) { h = displaymetrics.heightPixels - 200; w = displaymetrics.widthPixels - 100; } else { h = displaymetrics.heightPixels - 500; w = displaymetrics.widthPixels - 700; } } scaledBitmap = Bitmap.createScaledBitmap(mBitmap, w, h, false); } //Test 20/8/2017// public MyView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public MyView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context ctx) { scaleDetector = new ScaleGestureDetector(ctx, new ScaleListener()); } ///////////////// @Override protected void onDraw(Canvas canvas) { this.canvas = canvas; super.onDraw(canvas); DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); //Test 20/8/2017// canvas.scale(this.scaleFactor, this.scaleFactor, this.scaleDetector.getPreviousSpanX(),this.scaleDetector.getPreviousSpanY()); ////////////////// canvas.drawBitmap(scaledBitmap, 0, 0, paint); for (Path p : paths) { canvas.drawPath(p, paint); canvas.save(); } } @Override public boolean onTouchEvent(MotionEvent event) { //Test 20/8/2017// // scaleDetector.onTouchEvent(event); ////////////////// float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_UP: try { p1 = new Point(); p1.x = (int) x; p1.y = (int) y; drawnPoints.add(p1); final int sourceColor = scaledBitmap.getPixel((int) x, (int) y); final int targetColor = paint.getColor(); new TheTask(scaledBitmap, p1, sourceColor, targetColor).execute(); paths.add(path); invalidate(); } catch (Exception e) { e.printStackTrace(); } break; case MotionEvent.ACTION_MOVE: scaleDetector.onTouchEvent(event); break; } return true; } public void clear() { path.reset(); invalidate(); } public int getCurrentPaintColor() { return paint.getColor(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); w = widthMeasureSpec - MeasureSpec.EXACTLY; h = heightMeasureSpec - MeasureSpec.EXACTLY; Log.d("Dim", Integer.toString(w) + " | " + Integer.toString(h)); } class TheTask extends AsyncTask<Void, Integer, Void> { Bitmap bmp; Point pt; int replacementColor, targetColor; public TheTask(Bitmap bm, Point p, int sc, int tc) { this.bmp = bm; this.pt = p; this.replacementColor = tc; this.targetColor = sc; pd.show(); } @Override protected void onPreExecute() { pd.show(); } @Override protected void onProgressUpdate(Integer... values) { } @Override protected Void doInBackground(Void... params) { FloodFill f = new FloodFill(); f.floodFill(bmp, pt, targetColor, replacementColor); return null; } @Override protected void onPostExecute(Void result) { pd.dismiss(); invalidate(); } } private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { scaleFactor *= detector.getScaleFactor(); scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 10.0f)); invalidate(); return true; } } } public class FloodFill { public void floodFill(Bitmap image, Point node, int targetColor, int replacementColor) { int width = image.getWidth(); int height = image.getHeight(); int target = targetColor; int replacement = replacementColor; if (target != replacement) { Queue<Point> queue = new LinkedList<Point>(); do { int x = node.x; int y = node.y; while (x > 0 && image.getPixel(x - 1, y) == target) { x--; } boolean spanUp = false; boolean spanDown = false; while (x < width && image.getPixel(x, y) == target) { image.setPixel(x, y, replacement); if (!spanUp && y > 0 && image.getPixel(x, y - 1) == target) { queue.add(new Point(x, y - 1)); spanUp = true; } else if (spanUp && y > 0 && image.getPixel(x, y - 1) != target) { spanUp = false; } if (!spanDown && y < height - 1 && image.getPixel(x, y + 1) == target) { queue.add(new Point(x, y + 1)); spanDown = true; } else if (spanDown && y < height - 1 && image.getPixel(x, y + 1) != target) { spanDown = false; } x++; } } while ((node = queue.poll()) != null); } } } }
So please I need help to resolve the above problems.
Kindly let me know in case you need more details.
Thanks in advance.
Best regards,
Leenah.
0 comments:
Post a Comment