I have a precut image i.e One base image and multiple transparent layer of the the base image.
I am trying to add the layer image on top of base image to select the layer and apply different color on it.
I have tried the following way to achieve it but not able to finish.
ImageView - I am overlapping imageview with transparent layer image. It shows the blended image but the touch event detects the finally overlapped image id always. Because I draw the image with fill parent, all the layer image is also the same
Layer Drawable - It can allow only drawable images, but my use case is to load the precut from gallery or other resource. Even I can't select layer on touch.
GPUImage library - The image is not showing full imageview.
Regards
Sathiya
Extend the View class, make the onDraw() function draw what you want to draw. The onTouchEvent() function implement the touch events. What you're trying to do isn't subsumed in any view already made but it's pretty easy to make a view. Just draw the bitmaps on the canvas in the correct order with the correct paints with the right transparency.
#Override
protected void onDraw(Canvas canvas) {
int numLayers = mLayers.size();
for (int i = 0; i < numLayers; i++) {
canvas.save();
canvas.concat(matrix);
//or
canvas.translate(rect.left,rect.top);
Bitmap b = mLayers.get(i);
canvas.drawBitmap(b, paint);
canvas.restore();
}}
You end up doing this a bunch just adding bitmaps to the canvas in whatever places and order as needed.
Related
I am working on a program that lets you draw highlights, pen and text comment mark-up. I have a working version where I recycle a bmp 3 times then draw it to the canvas.
The issue is my app has 3 of these views in memory, so that is a lot of bmps being created.
In my current solution, I am trying to avoid bmps. I have extended an ImageView and added the following to the Draw event:
`
public override void Draw (Canvas canvas)
{
base.Draw (canvas);
HighlightLayer.Draw(canvas, Width, Height);
PenLayer.Draw(canvas, Width, Height);
TextLayer.Draw(canvas, Width, Height);
}
`
Note that I am using monodroid so it's C# (but nearly the same as Java) and all the "Layer" objects are a subclass of Drawable. Just assume they have draw path commands etc.
Anyway, it sort of works except all the highlights / pen have black boxes around them.
When I draw a line (that's not an eraser), I use PorterDuff.Mode.Src.
I tried to combine the 3 into one bmp instead of recycling it but the issue was that if I had an eraser vector it would erase anything that is already drawn. So an erased pen line would also erase the highlights ...
Is it possible to "freeze" a drawing so that as you continue to draw paths on the canvas and change the PorterDuff mode to clear it will not effect anything marked as freeze?
I know enough to know that the black box I am seeing around my lines on my Drawables is due to the background bmp not being set. The problem is I want them to be layers on top of the ImageView. If they each retained a background then you could not see the Drawables underneath. How can I use a drawable with the background of the "parent ImageView" and avoid the black background it assumes to be there.
Somehow I need the background of the "parent" ImageView to be applied to the Drawables when it's choosing the transparent fill to avoid the default black.
SOLUTION:
Using the suggestion below I created a LayerDrawable and added Drawables for each mark-up tool. In the Drawable, before drawing the lines I added the following code:
public override void Draw (Canvas canvas)
{
canvas.SaveLayer(new RectF(0,0,Bounds.Width(),Bounds.Height()), null, SaveFlags.All);
canvas.DrawColor(Color.Transparent, PorterDuff.Mode.Clear);
GraphicsUtil.DrawVector(canvas, Lines, ToolID, Bounds.Width(), Bounds.Height());
}
I got success in implementing a pinch zoom in/out and drag/drop functionality in images on the canvas.
Now what I want is re-sizing, that images like below link that based on iPhone App
How to change shape of an image using iPhone SDK?
So how can I achieve that kind of functionality in Android ?
Basically you need to invalidate the image and re-draw on the canvas from the beginning ::
img=(ImageView)findViewById(R.id.yourimageidfromxml);
img.onTouchEvent(MotionEvent me)
{
int X=me.getX();
int Y=me.getY();
img.invalidate();
img.repaint(X,Y);
}
void paint(int X,int Y)
{
img.setWidth(X);
img.setHeight(Y);
}
Scaling image will transform using repaint on canvas from the beginning
If by re-sizing you are referring to "stretching" the Bitmap on the vertical and horizontal plane then you simply modify the rect that the shape (eg. oval) is being drawn into.
For example:
This is your original shape of an oval:
canvas.drawOval(new Rect(0,0,100,100), bluePaint);
This is the same oval, just stretched (resized) on the horizontal plane:
canvas.drawOval(new Rect(0,0,200,100), bluePaint);
I hope this helps.
There are two options, both involving a custom view. The first is to create a custom view that fills your "canvas". You can keep track of 8 blue and 1 green circles in the view as Rect objects. Override onTouchEvent(MotionEvent) and then check if motion events are in any of your controls and update them accordingly (I'm simplifying things a bit here :)). From your onTouchEvent you would call invalidate(). You're onDraw(Canvas) can then handle drawing the controls and update the image according to how your controls have changed since the last call to onDraw.
The other option is to do something similar, but with a view that only encapsulates the circle and controls, meaning that moving the view around would require a container that will let the view change it's layout parameters. Doing this, your onTouchEvent method would need to trigger an invalidate with that layout view because it would need to recalculate the size and position of your view. This would definitely be harder but depending on what you are trying to achieve working with individual views may be better than maintaining representations of your circles in code in a single view.
The resizing of the image can be achieved by using a simple ImageView with scaleType "fitXY".
You have to add the blue resize handles yourself.
Changing the rotation of the image (green handle) can be achieved by using:
public static Bitmap rotate(Bitmap src, float degree) {
// create new matrix
Matrix matrix = new Matrix();
// setup rotation degree
matrix.postRotate(degree);
// return new bitmap rotated using matrix
return Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
}
Source: http://xjaphx.wordpress.com/2011/06/22/image-processing-rotate-image-on-the-fly/
See http://xjaphx.wordpress.com/learning/tutorials/ for more Android Image Processing examples.
I'm developing an app for Android, a small notepad app.
In my app I use a Gridview for create a grid of 2*X size and in each cell
I has a LinearLayout call AbstractNote that has in task to show a preview of each save
note in the app.
I what my AbstractNote to has a background image that is some bit rotate for show
the preview more beautifully. But my problems is while i rotate the image some of it falls outside of the AbstractNote Area, and I'not find a good way to show this to.
I has try to use View.setAnimation(...) and it works but give me rugged image and text,
and I has try to crate a custom Drawable (set as AbstractNote.setBackgroundDrawable(...)) that give me smooth image but not show the full image.
Do note, My target android is 2.1 and I not use View.setRotation(...)
Use a View.setAnimation for do this but get rugged image and text
Use custom drawable, but can't paint outside of the cell.
If somebody know how to fix it, by fix the rugged image and text in attempted 1 or
how to draw image outside the cell in attempted 2, I will be very grateful.
I has finally find a solution on the problem, the solution is not very good but work, the idea was to draw the cells item directly draw the background on the GridView and not the GridView childen/item
I Create a new GridView as:
public class NoteGridView extends GridView {
#Override
protected void dispatchDraw(Canvas canvas) {
final int count = getChildCount();
if (count > 0) {
for (int i = 0; i < this.getChildCount(); i++) {
// For each of my childen draw it backgrund that allow to draw bg that is bigger then cell.
View childAt = this.getChildAt(i);
if (childAt instanceof AbstractNote) {
final AbstractNote note = (AbstractNote) childAt;
// Set the zero point to the start of the childen, then call the childen draw methods.
canvas.save();
canvas.translate(childAt.getLeft(), childAt.getTop());
note.drawBackground(canvas);
canvas.restore();
}
}
}
super.dispatchDraw(canvas);
}
}
And in my children AbstractNote I add the method drawBackground, this do that background I what to draw in my AbstractNote is now draw on the GridView canvas that is much bigger then the small canvas I has in AbstractNote
I have a activity where I have two imageViews. In onTouch I recognize which imageView was clicked. Now I have a question. How I can draw new very small image in place where I clicked. I know that onTouch i have getX() and getY() and I save this position when I touch the screen, but I don't know how I can draw image in place where I clicked. My image is in drawable resources. I need to use canvas or is better way. I need draw this picture and after that I need run animation this image.
edit1: How can I set positionX and positionY my image. I have position where I click but I don't know how I can set image in this coordinates.
you should have a image view with visible attribute of FALSE and after touch (or any event you want) set three attribute : visible = true; x = getX() and y = getY();
is it enough or explain more?
I see the following approach.
Replace the ImageView by a custom view derived from ImageView.
Override onDraw.
call super.onDraw to draw the image
paint your image using onDraw's canvas at the last touch position.
each time you get a touch, you need to invalidate the custom view
I have two images.
An image with a red rectangle, and image all white. I would like to paint with your finger on the white image only where the other image is the red rectangle.
The image with the red rectangle should not be visible.
How can I do?
Create bounds for each image, e.g. with a Rect set to the cords of each image (position & size). In the view where your overriding onDraw() in, set the onTouchListener to the view itself.
In onTouch() check the event.getX()/getY() is within the bounds of the white image. Then use whiteImage.setPixel() to set the individual pixels of the Bitmap image. Alternatively use Canvas.drawPoint() instead of manipulating white bitmap image itself.
In regards to not displaying the red rectangle... just don't draw it?
Edit:
To your comment about non square/rect shapes. I would still check for the touch event in the rect and then pass it to the image if it has hit the shape.
Within the shape (I'm assuming it is a bitmap) you would do Bitmap.getPixel(x, y) and see if it is == to Color.White, if it is.. change it to whatever colour!