Ok the title might not be clear at first. Since one Youtube video is worth a thousand words here it is:
As you can see in the video above we can manipulate the closed path -which is composed of multiple paths- and clip the image underneath with the shape of the paths. There is an off-topic issue I would like to mention at this point. You may notice that the canvas drawing seems a little bit laggy in the video. That's not because I recorded it from an emulator (since I use Intel virtualization the emulator is pretty fast) but the canvas.clipPath does not support android hardware acceleration. So the emulator is slow without the hardware acceleration. However, this runs pretty neat in a phone. You can see the unsupported hardware acceleration functions here: http://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported So for this project android:hardwareAccelerated must be set to false.
Ok lets get back to the topic, I implemented this for a freelance job. The requirement was to create a photoshop like tool where you can put images on top of each other and clip the top image to stitch the images together (imagine you are trying to cut your friends head from a picture and paste it to another picture, you need to adjust the edges of the head to make the final image look pretty). Since the clipping was not needed to be too precise couple of curves was enough and since android already has most of the stuff implemented I just needed to combine them together.
The closed path is actually composed of several quadratic bezier curves. A bezier curve is a parametric curve. You specify some control points with a start and an end point. Then, by interpolation between your start and end point using your control point you create your curve.
I started with creating points to control my curves. We will call this class as BezierPoint.
The important features of this class is that it has the coordinates to represent the point and it holds a rectangular border in which you can put your finger to move the point. So it also has a function to check if the current point is selected by comparing your current touch point. It is really simple, it just checks if your finger is inside the rectangular box:
The border is specified by some constants namely RADIUS and SENSITIVITY the radius is also used to draw the point itself inside the canvas. The reason there are two variables is that you might want the size of the touch border to be different than the size of the point itself. These are used as follows:
Note that x and y is updated whenever the point is moved so the border is updated as well. The newX and newY variables are the new touch points of your finger.
After creating the class to hold the points we need the Curve class, we are going to call it as BezierCurve. This class is responsible for holding the points and their paints to be used while drawing. The points inside this class are used while doing the actual clipping. This class also has a method to check if its points are selected:
So you can think that the selection checking propagates from curves to points. Selection works as follows, when the user touches the screen, ACTION_DOWN catches the point and checks all the curves on the screen until it finds a match. Then in the ACTION_MOVE the selected points are moved. If there is no selected point the image is moved:
Now lets explain the real clipping.
The trick here is to just move the path to the beginning once. If you try to use moveTo for every curve, you are going to get a multiple clipping again but the center will not be visible. So that's not the clipping we are looking for. We iterate over every curve, moveTo the begining once and quadTo the remaining curves. Then draw the bitmap and other stuff as usual.
You can find the complete project in github: https://github.com/cdoger/Android-Image-Clipping