java - How to use BitmapShader without repeat -
i working on drawing app, want draw heart shape user finger touch mobile screen. setup bitmapshader below code
//initialize bitmap object loading image resources folder bitmap fillbmp = bitmapfactory.decoderesource(context.getresources(), r.drawable.heart); fillbmp = bitmap.createscaledbitmap(fillbmp, 20, 20, false); //initialize bitmapshader bitmap object , set texture tile mode shader= new bitmapshader(fillbmp, shader.tilemode.repeat, shader.tilemode.repeat);
then assign shader paint object.
paint.setshader(preset.shader);
i have setup touch listener track user finger. on user touch draw on canvas object as.
path path = new path(); path.moveto(mid1.x, mid1.y); path.quadto(midmid.x, midmid.y, mid2.x, mid2.y); canvas.drawpath(path, paint);
this give me this
where heart shape croped , these repeated. want not these repeated , never croped this.
thanks in advance.
i had bit of trouble uploading git, now, i'll post solution here.
here's helper class wrote create effect want. added comments in-line explain i'm doing.
import android.content.context; import android.graphics.bitmap; import android.graphics.bitmapfactory; import android.graphics.canvas; import android.graphics.paint; import android.graphics.path; import android.graphics.pathmeasure; // use class canvas create effect want. public class curvedbitmapdrawer { private context mcontext; private paint mpaint; private int mresourceid; private bitmap mbitmap; private path mpath; private int mbitmapmargin; // create context class can use resource ids. public curvedbitmapdrawer(context context) { mcontext = context; mpath = new path(); } // getters setters paint. // paint used draw bitmaps, , strokewidth value in paint // used set thickness of curve / line drawn. public paint getpaint() { return mpaint; } public void setpaint(paint paint) { mpaint = paint; } // getters setters space between bitmaps. public int getbitmapmargin() { return mbitmapmargin; } public void setbitmapmargin(int bitmapmargin) { mbitmapmargin = bitmapmargin; } // getters setters res id public int getresourceid() { return mresourceid; } public void setresourceid(int resourceid) { mresourceid = resourceid; mbitmap = null; } // alternative optional getters setters bitmap. public bitmap getbitmap() { return mbitmap; } public void setbitmap(bitmap bitmap) { mbitmap = bitmap; mresourceid = 0; } // decided use local path here, feel free change it. // call getpath perform actions on path drawn class. public path getpath() { return mpath; } // draw method. comments inline. public void draw(canvas canvas) { // grab bitmap in desired size. final bitmap scaledbitmap = getscaledbitmap(); // find center of bitmap. final float centerx = scaledbitmap.getwidth() / 2; final float centery = scaledbitmap.getheight() / 2; // wrap path measurement tool paths - pathmeasure final pathmeasure pathmeasure = new pathmeasure(mpath, false); // initialize distance center of bitmap. float distance = scaledbitmap.getwidth() / 2; // initialize position , slope buffers. float[] position = new float[2]; float[] slope = new float[2]; float slopedegree; // draw long distance traveled on path isn't longer // total distance of path. while (distance < pathmeasure.getlength()) { // grab position & slope (tangent) on particular distance along path. pathmeasure.getpostan(distance, position, slope); // convert vector degree. slopedegree = (float)((math.atan2(slope[1], slope[0]) * 180f) / math.pi); // preserve current state of canvas canvas.save(); // translate canvas position on path. canvas.translate(position[0] - centerx, position[1] - centery); // rotate canvas around center of bitmap amount of degrees needed. canvas.rotate(slopedegree, centerx, centery); // draw bitmap canvas.drawbitmap(scaledbitmap, 0, 0, mpaint); // revert bitmap previous state canvas.restore(); // increase distance bitmap's width + desired margin. distance += scaledbitmap.getwidth() + mbitmapmargin; } } // returns scaled bitmap asset specified. private bitmap getscaledbitmap() { // no bitmap or resid, return null (no special handing of this! add if like). if (mbitmap == null && mresourceid == 0) return null; // if no bitmap specified, create 1 resource id. // optimization: sure clear bitmap once done. if (mbitmap == null) mbitmap = bitmapfactory.decoderesource(mcontext.getresources(), mresourceid); // width / height of bitmap[ float width = mbitmap.getwidth(); float height = mbitmap.getheight(); // ratio of bitmap float ratio = width / height; // set height of bitmap width of path (from paint object). float scaledheight = mpaint.getstrokewidth(); // maintain aspect ratio of bitmap, use height * ratio width. float scaledwidth = scaledheight * ratio; // return generated bitmap, scaled correct size. return bitmap.createscaledbitmap(mbitmap, (int)scaledwidth, (int)scaledheight, true); } }
here's usage example:
imageview image = (imageview)findviewbyid(r.id.img); curvedbitmapdrawer drawer = new curvedbitmapdrawer(this); paint paint = new paint(); paint.setstrokewidth(50); drawer.setpaint(paint); drawer.setresourceid(r.drawable.heart_icon); drawer.setbitmapmargin(10); path path = drawer.getpath(); path.moveto(80, 90); path.cubicto(160, 470, 750, 290, 440, 880); bitmap finalbitmap = bitmap.createbitmap(800, 1000, bitmap.config.argb_8888); canvas canvas = new canvas(finalbitmap); drawer.draw(canvas); image.setimagebitmap(finalbitmap);
i've tested here , seems work well, minus edge cases perhaps. here's looks given usage example:
remember set stroke width on paint object supply, or else nothing drawn (and cause exception current code).
hope helps you.
Comments
Post a Comment