I am working on an App with coloring function. User can perform pan and zooming on this image. I am using this library to add zoom effect on image.
But the issue is when I zoom the image, I am not able to color to specific areas of image. In small view it works perfect but after zooming when i touch on an area it fills color to different area instead of touching area.
The reason is only one that the original image laying under is not getting scaled even when I zoom the image on the top. I searched and found this answer this is the same issue which I have but I am not understanding where and how to use this in my activity.java file.
This is my ActivityClass
package com.coloringbook;
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.app.WallpaperManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Shader.TileMode;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import android.widget.LinearLayout.LayoutParams;
import com.coloringbook.R;
import com.onesignal.OneSignal;
public class Game extends Activity implements View.OnLongClickListener, View.OnClickListener, View.OnTouchListener {
private TouchImageView image;
Bitmap bm_iv; //bitmap for image view for coloring
int bm_iv_dx; //sizes
int bm_iv_dy;
int[] pixels; //of bm_iv; need to fill by color
final int[] colors_base = {0xff0000,0xff8000,0xffff00,0x80ff00,0x00ff00,0x00ff80,0x00ffff,0x0080ff,
0x0000ff,0x8000ff,0xff00ff,0xff0080,0x888888}; //default palette
final int btn_num = colors_base.length;
int[] colors_gradient = new int[btn_num]; //gradient palette, will generate dynamically
Bitmap bm_gradient; //to draw gradient and fill gradient buttons
Bitmap[] bm_button_on = new Bitmap[btn_num*2]; //bitmaps for color buttons
Bitmap[] bm_button_off = new Bitmap[btn_num*2];
Bitmap[] bm_button_pressed = new Bitmap[btn_num*2];
int size_button; // size of color button, depend of screen resolution
final int color_gradient_shift = 3; // to avoid dark colors
int color_selected; // index of current color
int color_base_selected; // index of base color
static int bitmap_saved_counter; // to generate name to save on SD card
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Data.SetFullScreenMode(this);
setContentView(R.layout.game);
Data.ShowAdMob(this);
image = (TouchImageView) findViewById(R.id.book);
bm_gradient = Bitmap.createBitmap(btn_num+2+color_gradient_shift, 1, Config.ARGB_8888);
LinearLayout ll_root = (LinearLayout)findViewById(R.id.mainLayout);
ll_root.setOnLongClickListener( this );
DisplayMetrics dm = getResources().getDisplayMetrics();
size_button = dm.widthPixels/btn_num;
int i;
LinearLayout ll_base = new LinearLayout(this);
ll_base.setOrientation(LinearLayout.HORIZONTAL);
ll_base.setLayoutParams(new LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT));
LinearLayout ll_gradient = new LinearLayout(this);
ll_gradient.setOrientation(LinearLayout.HORIZONTAL);
ll_gradient.setLayoutParams(new LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT));
for( i = 0; i < btn_num; i++){
ImageButton ib = new ImageButton(this);
ib.setId( Data.id_image_begin+i);
ib.setPadding(0, 0, 0, 0);
ib.setBackgroundDrawable(null);
ib.setOnClickListener(this);
ll_base.addView(ib);
ib = new ImageButton(this);
ib.setId( Data.id_image_begin+i+btn_num);
ib.setPadding(0, 0, 0, 0);
ib.setBackgroundDrawable(null);
ib.setOnClickListener(this);
ll_gradient.addView(ib);
}
ll_root.addView(ll_base);
ll_root.addView(ll_gradient);
UpdateButtons();
InitImage("");
}
void InitImage( String filePath ){
bm_iv = null;
File file = new File(filePath);
if( file.isFile() ){
Options opts = new Options();
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
opts.inScaled = false;
bm_iv = BitmapFactory.decodeFile( filePath, opts);
}
if( bm_iv == null ){
int id = getResources().getIdentifier( "book_"+ Data.image_index, "drawable", getPackageName());
bm_iv = BitmapFactory.decodeResource( getResources(), id);
}
bm_iv_dx = bm_iv.getWidth();
bm_iv_dy = bm_iv.getHeight();
DisplayMetrics dm = getResources().getDisplayMetrics();
if( dm.widthPixels >= bm_iv_dx && dm.heightPixels >= bm_iv_dy ){
}else{
float scale_x = (float) bm_iv_dx/(float) dm.widthPixels;
float scale_y = (float) bm_iv_dy/(float) dm.heightPixels;
float scale = Math.max(scale_x, scale_y);
bm_iv_dx/=scale;
bm_iv_dy/=scale;
bm_iv = Bitmap.createScaledBitmap(bm_iv, bm_iv_dx, bm_iv_dy, true);
}
bm_iv = bm_iv.copy(Config.ARGB_8888, true); //need convert to mutable bitmap
ImageView iv = (ImageView)findViewById(R.id.book);
iv.setImageBitmap( bm_iv );
pixels = new int[bm_iv_dx*bm_iv_dy];
int x, y;
//initialization black contours
for( y = 0; y < bm_iv_dy; y++ ){
for( x = 0; x < bm_iv_dx; x++ ){
int color = bm_iv.getPixel(x, y);
if(Color.red(color) <= 0x80 && Color.green(color) <= 0x80 && Color.blue(color) <= 0x80){
pixels[y*bm_iv_dx+x] = -1;
}else{
pixels[y*bm_iv_dx+x] = 0;
}
}
}
iv.setOnTouchListener( this );
}
static int ColorShader( int color, int devider){
int r = Color.red(color);
int g = Color.green(color);
int b = Color.blue(color);
r -= r/devider;
g -= g/devider;
b -= b/devider;
return Color.argb(255, r, g, b);
}
boolean IsValidXY( int x, int y){
if( 0 <= x && x < bm_iv_dx && 0 <= y && y < bm_iv_dy ){
return true;
}else{
return false;
}
}
boolean FillPixel( int x, int y, int color_fill ){
if( IsValidXY(x,y) ){
if( pixels[y*bm_iv_dx+x] == 0 ){
pixels[y*bm_iv_dx+x] = color_fill;
return true;
}else{
return false;
}
}else{
return false;
}
}
//create rounded square solid color bitmap
Bitmap GetButtonBitmap( int size_button, int color, int round, int border ){
Bitmap bm = Bitmap.createBitmap( size_button, size_button, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(color);
paint.setAlpha(255);
paint.setStyle(Paint.Style.FILL);
c.drawRoundRect(new RectF(border,border,size_button-border, size_button-border), round, round, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
paint.setColor(ColorShader(color,2));
c.drawRoundRect(new RectF(border,border,size_button-border, size_button-border), round, round, paint);
return bm;
}
//set images to all color buttons
void SetButtons(){
for( int i = 0; i < btn_num; i++){
ImageButton ib = (ImageButton) findViewById(Data.id_image_begin+i);
StateListDrawable states = new StateListDrawable();
Drawable d = new BitmapDrawable( getResources(), bm_button_pressed[i]);
states.addState(new int[] {android.R.attr.state_pressed}, d);
d = new BitmapDrawable( getResources(), (color_selected == i) ? bm_button_on[i]:bm_button_off[i]);
states.addState(new int[]{}, d );
ib.setImageDrawable(states);
ib = (ImageButton) findViewById(Data.id_image_begin+i+btn_num);
states = new StateListDrawable();
d = new BitmapDrawable( getResources(), bm_button_pressed[i+btn_num]);
states.addState(new int[] {android.R.attr.state_pressed}, d);
d = new BitmapDrawable( getResources(), (color_selected == i+btn_num) ? bm_button_on[i+btn_num]:bm_button_off[i+btn_num]);
states.addState(new int[]{}, d );
ib.setImageDrawable(states);
}
}
//regenerate gradient colors and create solid color bitmaps to image buttons
public void UpdateButtons(){
//set gradient by base color
int i;
int color = 0xff000000|colors_base[color_base_selected];
Canvas canvas = new Canvas(bm_gradient);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
LinearGradient shader = new LinearGradient(0, 0, bm_gradient.getWidth(), 0, new int[] { Color.BLACK, color, Color.WHITE }, null, TileMode.CLAMP);
paint.setShader(shader);
canvas.drawPaint(paint);
for( i = 0; i < btn_num; i++){
colors_gradient[i] = bm_gradient.getPixel(i+1+color_gradient_shift, 0);
}
int round = size_button/8; //of square
int border = size_button/16; //to small not selected buttons
for( i = 0; i < btn_num; i++){
bm_button_on[i] = GetButtonBitmap( size_button, colors_base[i], round, 0 );
bm_button_off[i] = GetButtonBitmap( size_button, colors_base[i], round, border );
bm_button_pressed[i] = GetButtonBitmap( size_button, ColorShader(colors_base[i],2), round, 0 );
bm_button_on[ btn_num+i] = GetButtonBitmap( size_button, colors_gradient[i], round, 0 );
bm_button_off[btn_num+i] = GetButtonBitmap( size_button, colors_gradient[i], round, border );
bm_button_pressed[btn_num+i] = GetButtonBitmap( size_button, ColorShader(colors_gradient[i],2), round, 0 );
}
SetButtons();
}
@Override
public void onClick( View v ) { //color buttons
int index = v.getId() - Data.id_image_begin;
color_selected = index;
if( index < btn_num ){
color_base_selected = index;
UpdateButtons();
}else{
SetButtons();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.game_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected( MenuItem item ) {
switch( item.getItemId() ){
case R.id.load_image:
startActivityForResult( new Intent( Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI), 0);
break;
case R.id.save_to_galary:
Images.Media.insertImage( getContentResolver(), bm_iv, getString(R.string.app_name)+(bitmap_saved_counter++), null);
break;
case R.id.set_as_wallpaper_landscape:
case R.id.set_as_wallpaper_portrait:
DisplayMetrics dm = getResources().getDisplayMetrics();
Bitmap bm;
int add_x, add_y;
if( item.getItemId() == R.id.set_as_wallpaper_landscape ){
bm = Bitmap.createBitmap( dm.heightPixels*2, dm.widthPixels*2, Bitmap.Config.ARGB_8888);
}else{
bm = Bitmap.createBitmap( dm.widthPixels*2, dm.heightPixels*2, Bitmap.Config.ARGB_8888);
}
add_x = (bm.getWidth() - bm_iv.getWidth())/2;
add_y = (bm.getHeight() - bm_iv.getHeight())/2;
bm.eraseColor( bm_iv.getPixel(0, 0) );
Canvas canvas = new Canvas(bm);
canvas.drawBitmap(bm_iv, add_x, add_y, null);
WallpaperManager wm = WallpaperManager.getInstance(getApplicationContext());
try {
wm.setBitmap(bm);
} catch (IOException e) {
Toast.makeText( this, "Upps. Can not set as wallpaper.", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
break;
}
return true;
}
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent){
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
if(resultCode == RESULT_OK){
Uri selectedImage = imageReturnedIntent.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String filePath = cursor.getString(columnIndex);
cursor.close();
InitImage(filePath);
}
}
public boolean onLongClick( View view) { // on screen
this.openOptionsMenu();
return false;
}
@Override
public void openOptionsMenu() { //need to work menu on some devices, fix the bug
Configuration config = getResources().getConfiguration();
if((config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) > Configuration.SCREENLAYOUT_SIZE_LARGE) {
int originalScreenLayout = config.screenLayout;
config.screenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
super.openOptionsMenu();
config.screenLayout = originalScreenLayout;
} else {
super.openOptionsMenu();
}
}
@Override
public boolean onTouch(View v, MotionEvent event) { // on coloring book
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int x_touch = (int)event.getX();
int y_touch = (int)event.getY();
if( IsValidXY(x_touch,y_touch) == false || pixels[y_touch*bm_iv_dx+x_touch] == -1 ){ //touch on contour
return false;
}
ImageView iv_touch = (ImageView)findViewById(R.id.book);
int x,y;
//clear
for( y = 0; y < bm_iv_dy; y++ ){
for( x = 0; x < bm_iv_dx; x++ ){
if( pixels[y*bm_iv_dx+x] != -1 ){
pixels[y*bm_iv_dx+x] = 0;
}
}
}
int color_fill = 0;
if( color_selected < btn_num){
color_fill = colors_base[color_selected];
}else{
color_fill = colors_gradient[color_selected-btn_num];
}
color_fill |= 0xff000000;
pixels[y_touch*bm_iv_dx+x_touch] = color_fill;
//filler
int xx,yy;
while( true ){
boolean go = false;
for( y = 0; y < bm_iv_dy; y++ ){
for( x = 0; x < bm_iv_dx; x++ ){
if( pixels[y*bm_iv_dx+x] == color_fill ){
go |= FillPixel(x,y-1,color_fill);
go |= FillPixel(x+1,y-1,color_fill);
go |= FillPixel(x+1,y,color_fill);
go |= FillPixel(x+1,y+1,color_fill);
go |= FillPixel(x,y+1,color_fill);
go |= FillPixel(x-1,y+1,color_fill);
go |= FillPixel(x-1,y,color_fill);
go |= FillPixel(x-1,y-1,color_fill);
if( IsValidXY(x-1,y) && pixels[y*bm_iv_dx+x-1] == color_fill ){
xx = x-2;
while( FillPixel(xx--,y,color_fill) ){}
}
if( IsValidXY(x+1,y) && pixels[y*bm_iv_dx+x+1] == color_fill ){
xx = x+2;
while( FillPixel(xx++,y,color_fill) ){}
}
if( IsValidXY(x,y-1) && pixels[(y-1)*bm_iv_dx+x] == color_fill ){
yy = y-2;
while( FillPixel(x,yy--,color_fill) ){}
}
if( IsValidXY(x,y+1) && pixels[(y+1)*bm_iv_dx+x] == color_fill ){
yy = y+2;
while( FillPixel(x,yy++,color_fill) ){}
}
}
}
}
if( go == false ){
break;
}
}
//update pixels
for( y = 0; y < bm_iv_dy; y++ ){
for( x = 0; x < bm_iv_dx; x++ ){
if( pixels[y*bm_iv_dx+x] == color_fill ){
bm_iv.setPixel(x, y, color_fill);
}
}
}
iv_touch.invalidate();
}
return false;
}
}
Here is ImageTouchView.java which I am using for zoom
I really thankfull if anyone can help me.