Hi i guess this is quite simple solution but i cant figure it out myself.
lets say we have 4 points ( start_X, start_Y, end_X, end_Y) and we have to show the user this selection.
For now i thought best solution was to have 3 imageviews:
Original(nothing changed);
Mask(just any semi transparent color)
Portion(cutted out portion of original image)
and to show them as folows: 3>2>1
This solution would be great but i cant finish it. Stuck at croping an image portion and inserting it in 'the place' it belongs according to original image;
Questions are - Is there any other solution for this problem ? if not then - How to crop part of image using those 4 points and then put this image very exact place it belongs ?
Udate 1
Create new bitmap with transparent background (.png maybe) and same size as original image. Then add the cutted portion to it at special position and use it as image 3(described above); Is this solution correct ? if yes how to do it ?
try this:
class BD extends BitmapDrawable {
private Rect mSelection;
public BD(Resources res, Bitmap bitmap) {
super(res, bitmap);
mSelection = new Rect(20, 20, 60, 60);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
Log.d(TAG, "draw " + canvas.getMatrix());
canvas.clipRect(mSelection, Op.DIFFERENCE);
canvas.drawColor(0x66000000);
}
}
test code (place it in onCreate):
ImageView iv = new ImageView(this);
Resources res = getResources();
Bitmap b = BitmapFactory.decodeResource(res, R.drawable.layer0);
Drawable d = new BD(res, b);
iv.setImageDrawable(d);
setContentView(iv);
Related
I am using the FingerPaintCanvasView from this xamarin sample.
I am working with 2 layers. The first layer is an ImageView i want to draw on. The second layer is the PaintCanvasView to draw.
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent">
<ImageView
android:id="#+id/markImageImageView"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<fingerpaint.FingerPaintCanvasView
android:id="#+id/canvasMarkMeta"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
The canvas has a transparent background and the layout params of both views are set programmatically. This way the marking works fine.
Now the question is, how can I merge this imageview with the marking canvas with as little as possible quality loss to an singel file (bitmap or imageFile in FileSystem).
Let me explain why I mentiond the quality loss:
For example the image in the background has a size of 1920x1080 from the devices camera. The display only has 1280x800 pixel. Since I can't fit the image in the display, I need to display a scaled down version AND the marking happens on this scaled down version.
EDIT:
#Joe LV:
This is your demo without any changes deployed on my devices:
Lenovo Yoga 3, Android 6.0.1
Huawei Honor 8, Android 7.0
I will try an Android 8 Emulator soon.
Pixel 2XL, Android 8.1
So this method does not Work for API <= 24 :-(
(API 25 and 26 not tested)
markImageImageView just holds an image that I load from the device storage (can be any image)
canvasMarkMeta is the FingerPaintCanvas from the linked template which the holds the drawn lines.
Below is the code, I have add comments in it:
public class MainActivity : Activity
{
private Rect mSrcRect, mDestRect;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
//your background picture ---markImageImageView
Bitmap background = BitmapFactory.DecodeResource(Resources, Resource.Drawable.pause);
//your foreground picture ---FingerPaintCanvasView
Bitmap foreground = BitmapFactory.DecodeResource(Resources, Resource.Drawable.play);
Paint p = new Paint();
p.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.SrcOver));
//use background to create a canvas
Bitmap workingBitmap = Bitmap.CreateBitmap(background);
Bitmap mutableBitmap = workingBitmap.Copy(Bitmap.Config.Argb8888, true);
Canvas c = new Canvas(mutableBitmap);
int mBWith = background.Width;
int mBHeight = background.Height;
int mFWith = foreground.Width;
int mFHeight = foreground.Height;
mSrcRect = new Rect(0, 0, mBWith, mBHeight);
mDestRect = new Rect(0, 0, mFWith, mFHeight);
//draw foreground on the backaground, then they will be single bitmap
c.DrawBitmap(foreground, mSrcRect, mDestRect, p);
ImageView imageView = FindViewById<ImageView>(Resource.Id.iv);
imageView.SetImageBitmap(mutableBitmap);
}
}
And I have provide the demo on github.
Update:
Change Bitmap.Config.Argb4444 to Bitmap.Config.Argb8888.
I am want to display Barcode on android. As input I get SVG string. As a SVG library I use AndroidSVG. I used sample code from library website and everything seem to be fine. But when I zoom on image, I get distorted edges (Anti-alias?). I tried to disable all the flags. But the image still has fuzzy edges. What can be wrong with my code?
Picture:
Try to zoom to max, you will see the fuzzy edges.
Code:
private void loadQRCode(String svgString) {
SVG svg = null;
try {
svg = SVG.getFromString(svgString);
} catch (SVGParseException e) {
e.printStackTrace();
}
if (svg.getDocumentWidth() != -1) {
int widthPx = Utils.pxFromDp(400);
int heightDp = Utils.pxFromDp(300);
svg.setDocumentWidth(widthPx);
svg.setDocumentHeight(heightDp);
int width = (int) Math.ceil(svg.getDocumentWidth());
int height = (int) Math.ceil(svg.getDocumentHeight());
Bitmap newBM = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas bmcanvas = new Canvas(newBM);
final DrawFilter filter = new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG| Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG, 0);
bmcanvas.setDrawFilter(filter);
barcode.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
bmcanvas.drawRGB(255, 255, 255);
svg.renderToCanvas(bmcanvas);
barcode.setImageBitmap(newBM);
}
}
If the edges of the bars do not lie exactly on pixel boundaries, you will get anti-aliasing. On a high resolution screen, this should not normally be visible.
However, in your code, you are rendering the SVG to a bitmap and setting the bitmap to an ImageView. If that ImageView has a size larger than the bitmap - ie. greater than 400 x 300, then the anti-aliased pixels in that bitmap will likely be rendered larger and thus more visible.
One solution is to avoid using a bitmap. Use a Picture/PictureDrawable instead. That way the barcode will be rendered at highest quality no matter what size it is. As vector graphics are supposed to be.
Follow the example on this page:
http://bigbadaboom.github.io/androidsvg/use_with_ImageView.html
So your code should probably look something like the following:
private void loadQRCode(String svgString) {
try {
SVG svg = SVG.getFromString(svgString);
barcode.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
Drawable drawable = new PictureDrawable(svg.renderToPicture());
barcode.setImageDrawable(drawable);
} catch (SVGParseException e) {
e.printStackTrace();
}
}
If for some reason you need to use bitmaps - maybe you are caching them or something - then you should watch for changes in the size of the ImageView and then recreate the bitmap at the new size. So the bitmap is always the same size as the ImageView to which it is assigned.
Page Curl animation i am being using.
I wanted to ask Harism that how am i suppose to change the images after all of them are drawn once.
For eg. I have 10 Images Drawn on the First Instance for 10 pages, now when i come back from some other Activity I want to get the same pages to show modified 10 pages according to the (now) new/modified data, Currently i get my New/modified Data appended to the first 10 pages and thus i get a result of 20 pages, instead of only 10.
Can anyone working with the Curl animation help me in this?
Thanking in anticipation !!
private class BitmapProvider implements CurlView.BitmapProvider {
#Override
public Bitmap getBitmap(int width, int height, int index) {
// LinearLayout linearLayout=(LinearLayout) findViewById(R.id.linearLayout1);
Bitmap b = Bitmap.createBitmap(width,height,
Bitmap.Config.ARGB_8888);
b.eraseColor(Color.BLACK);
Canvas c = new Canvas(b);
TextView textPageCount= new TextView(AllQuotesActivity.this);
textPageCount.setText((index+1) +" of " + (allQuotes.size()));
textPageCount.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM);
textPageCount.setTextColor(Color.WHITE);
textPageCount.setTypeface(Typeface.createFromAsset(getAssets(), "Samba.ttf"));
textPageCount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
textPageCount.setLayoutParams(new LayoutParams(c.getWidth(),c.getHeight()));
fLayout.addView(textPageCount);
fLayout.setBackgroundColor(Color.BLACK);
fLayout.measure(c.getWidth(), c.getHeight());
fLayout.layout(0, 0, c.getWidth(), c.getHeight());
fLayout.draw(c);
return b;
}
// I actually call all of these instantiating methods while refreshing the CurlView in hopes that it wouldn't Append the Pages and reDraw it.
mCurlView = (CurlView) findViewById(R.id.curl);
mCurlView.sendClassInstance(this);
mCurlView.setBitmapProvider(new BitmapProvider());
mCurlView.setSizeChangedObserver(new SizeChangedObserver());
mCurlView.setCurrentIndex(index);
mCurlView.setAllowLastPageCurl(false);
// mCurlView.setBackgroundColor(0xFF202830);
mCurlView.setBackgroundColor(Color.BLACK);
Did you try setting the updated image directly to the corresponding index in the mBitmapIds int[].
Noob to game development and I'm having trouble placing an AnimationDrawable onto a SurfaceView canvas. It's part of a simple game, user touches screen and an animated gif is placed at that location that looks like an explosion. I can accomplish this with a Bitmap using the code shown below, but converting this to an AnimationDrawable is where I'm stuck. I could create the AnimationDrawable from an ImageView, but I can't find a way to get the ImageView onto the canvas either...
Am I going about this in the wrong way? Is there a simpler way to get an animated gif to display at an x,y coordinate on a SurfaceView's canvas?
Bitmap explodeBmp = BitmapFactory.decodeResource(getResources(), R.drawable.explode4);
canvas.drawBitmap(explodeBmp, coords.getX()-(explodeBmp.getWidth()/2), coords.getY()-(explodeBmp.getHeight()/2), paint);
This throws a ClassCastException if I try to convert the Bitmap to an AnimationDrawable and start it:
AnimationDrawable explosionAnimation = (AnimationDrawable) ((Drawable) new BitmapDrawable(explodeBmp));
explosionAnimation.start();
After continuous digging I've found the answer... seems I like answering my own questions here.
Just found the Movie class. I can load my animated gif into it using an InputStream, then play the movie bit by bit in my onDraw() because the Movie class supports a draw() method where I can supply my canvas and x,y coordinates.
Here's the code snippit below:
InputStream is = context.getResources().openRawResource(R.drawable.dotz_explosion);
Movie explodeGif = Movie.decodeStream(is);
...
#Override
protected void onDraw(Canvas canvas) {
...
GraphicObject explosion = (GraphicObject)ex.next();
long now = android.os.SystemClock.uptimeMillis();
if (explosion.getMovieStart() == 0) { // first time
explosion.setMovieStart(now);
}
int relTime = (int)((now - explosion.getMovieStart()) % explodeGif.duration());
if ((now - explosion.getMovieStart()) >= explodeGif.duration()) {
removeArrayExplosions.add(removeIndex);
explosion.setMovieStart(0);
} else {
explodeGif.setTime(relTime);
explodeGif.draw(canvas, explosion.getX()-(explodeGif.width()/2), explosion.getY()-(explodeGif.height()/2));
}
}
...
}
I have two png image files that I would like my android app to combine programmatically into one png image file and am wondering if it is possible to do so? if so, what I would like to do is just overlay them on each other to create one file.
the idea behind this is that I have a handful of png files, some with a portion of the image on the left with the rest transparent and the others with an image on the right and the rest transparent. and based on user input it will combine the two to make one file to display. (and i cant just display the two images side by side, they need to be one file)
is this possible to do programmatically in android and how so?
I've been trying to figure this out for a little while now.
Here's (essentially) the code I used to make it work.
// Get your images from their files
Bitmap bottomImage = BitmapFactory.decodeFile("myFirstPNG.png");
Bitmap topImage = BitmapFactory.decodeFile("myOtherPNG.png");
// As described by Steve Pomeroy in a previous comment,
// use the canvas to combine them.
// Start with the first in the constructor..
Canvas comboImage = new Canvas(bottomImage);
// Then draw the second on top of that
comboImage.drawBitmap(topImage, 0f, 0f, null);
// comboImage is now a composite of the two.
// To write the file out to the SDCard:
OutputStream os = null;
try {
os = new FileOutputStream("/sdcard/DCIM/Camera/" + "myNewFileName.png");
comboImage.compress(CompressFormat.PNG, 50, os)
} catch(IOException e) {
e.printStackTrace();
}
EDIT :
there was a typo,
So, I've changed
image.compress(CompressFormat.PNG, 50, os)
to
bottomImage.compress(CompressFormat.PNG, 50, os)
You can do blending. This is not particular to Android. It's just universal image processing.
EDIT:
You may find these articles & samples & code useful:
http://www.jhlabs.com/ip/
http://kfb-android.blogspot.com/2009/04/image-processing-in-android.html
http://code.google.com/p/jjil/
Image Processing on Android
I use this code
private class PhotoComposition extends AsyncTask<Object, Void, Boolean> {
private String pathSave;//path save combined images
#Override
protected Boolean doInBackground(Object... objects) {
List<String> images = (List<String>) objects[0]; //lsit of path iamges
pathSave = (String) objects[1];//path save combined images
if (images.size() == 0) {
return false;
}
List<Bitmap> bitmaps = new ArrayList<>();
for (int i = 0; i < images.size(); i++) {
bitmaps.add(BitmapFactory.decodeFile( images.get(i)));
}
int width = findWidth(bitmaps);//Find the width of the composite image
int height = findMaxHeight(bitmaps);//Find the height of the composite image
Bitmap combineBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);//create bitmap of composite image
combineBitmap.eraseColor(Color.parseColor("#00000000")); //bcakgraound color of composite image
Bitmap mutableCombineBitmap = combineBitmap.copy(Bitmap.Config.ARGB_8888, true);//create mutable bitmap to create canvas
Canvas canvas = new Canvas(mutableCombineBitmap);// create canvas to add bitmaps
float left = 0f;
for (int i = 0; i < bitmaps.size(); i++) {
canvas.drawBitmap(bitmaps.get(i), left, 0f, null);//Taking photos horizontally
left += bitmaps.get(i).getWidth();//Take right to the size of the previous photo
}
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(pathSave);//path of save composite image
mutableCombineBitmap.compress(Bitmap.CompressFormat.PNG, 80, outputStream);
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
#Override
protected void onPostExecute(Boolean isSave) {
if (isSave) {
//iamge save on pathSave
Log.i("PhotoComposition", "onPostExecute: " + pathSave);
}
super.onPostExecute(isSave);
}
private int findMaxHeight(List<Bitmap> bitmaps) {
int maxHeight = Integer.MIN_VALUE;
for (int i = 0; i < bitmaps.size(); i++) {
if (bitmaps.get(i).getHeight() > maxHeight) {
maxHeight = bitmaps.get(i).getHeight();
}
}
return maxHeight;
}
private int findWidth(List<Bitmap> bitmaps) {
int width = 0;
for (int i = 0; i < bitmaps.size(); i++) {
width += bitmaps.get(i).getWidth();
}
return width;
}
USAGE
List<String> images = new ArrayList<>();
images.add("/storage/emulated/0/imageOne.png");//path of image in storage
images.add("/storage/emulated/0/imageTwo.png");
// images.add("/storage/emulated/0/imageThree");
// ... //add more images
String pathSaveCombinedImage = "/storage/emulated/0/CombinedImage.png";//path save result image
new PhotoComposition().execute(images, pathSaveCombinedImage);
And the result of using the above code will be as follows
You may wish to look into the Canvas object, which would make it easy to do other drawing operations as well. You can just draw your bitmaps onto a canvas where you want them, then save the resulting bitmap.
If they have transparent sections, then if you draw one on top of the other, only the non-transparent portions will overlap. It will be up to you to arrange the bitmaps however you like.
For the separate issue of re-saving your image to a png, use bitmap.compress().
Try this .
public Bitmap mergeBitmap(Bitmap frame, Bitmap img){
Bitmap bmOverlay = Bitmap.createBitmap(frame.getWidth(), frame.getHeight(), frame.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(img, 0, 0, null);
canvas.drawBitmap(frame, new Matrix(), null);
return bmOverlay;
}
Returns a bitmap image
Pass two bitmap images to your function as shown below
Bitmap img= mergeBitmap(imgone, imagetwo);
See the entire post or also see merge multiple images in android programmatically