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.
Related
Are there any APIs for changing the look of the current location icon used during navigation. I was able to modify it using a custom Map marker and updating the position using the position manager callbacks but I'm wondering if there is an easier way. Also it wasn't clear how I could change the heading of the icon (I'm replacing the circle with an arrow). I'd like to be able to rotate the arrow appropriately during maneuvers. It looks as if the HERE app does this sort of thing so I'm wondering if any of these APIs are exposed in the SDK.
Generally we encourage developers to build their own position indicators using the MapMarker or MapLocalModel APIs. There are too many customization options for us to make a generic position indicator :)
Please create a map object and customize the behaviour as needed for your application.
Create image object
try
{
Image image = new Image();
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.store_pin);
Bitmap scaledBitmap = Utility.scaleDown(icon, 150, true);
image.setBitmap(scaledBitmap);
customMarker = new MapMarker(new GeoCoordinate(destLat, destLng, 0.0), image);
map.addMapObject(customMarker);
}
catch(IOException e) {
e.printStackTrace();
}
On you indicator
mapFragment.getPositionIndicator().setVisible(true);
mapFragment.getPositionIndicator().setMarker(image);
To resize your Bitmap(Marker image)
public static Bitmap scaleDown(Bitmap realImage, float maxImageSize, boolean filter) {
float ratio = Math.min((float) maxImageSize / realImage.getWidth(),(float) maxImageSize / realImage.getHeight());
int width = Math.round((float) ratio * realImage.getWidth());
int height = Math.round((float) ratio * realImage.getHeight());
Bitmap newBitmap = Bitmap.createScaledBitmap(realImage, width, height, filter);
return newBitmap;
}
You have to create an Image objects
Image img = new Image();
try {
img.setImageResource(R.drawable.marker);
} catch (IOException e) {
e.printStackTrace();
}
Then you have to make sure that you add those two lines:
mapFragment.getPositionIndicator().setVisible(true);
mapFragment.getPositionIndicator ().setMarker (img);
It worked for me like this.
Am creating a document scanning application in android, am using OpenCV and Scan library in my project for cropping,I have created a rectangle using drawrect in camera view, now I need to capture the images inside that rectangle portion only and display it in another activity.
The image in question:
For me , I will take whole image, then crop.
Your question : "how do I know which part of the image is inside the rectangular portion, then only I can pass it nah, hope u understood". My answer is you can using relativity scaling of whole image dimension and camera display screen dimension. Then you will know which part of rectangular to be cropped.
This is the code example.
Note that you need to fill some codes to make it can save file into jpg, and save it after cropped.
// 1. Save your bitmap to file
public class MyPictureCallback implements Camera.PictureCallback {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
//mPictureFile is a file to save the captured image
FileOutputStream fos = new FileOutputStream(mPictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
}
}
}
// Somewhere in your code
// 2.1 Load bitmap from your .jpg file
Bitmap bitmap = BitmapFactory.decodeFile(path+"/mPictureFile_name.jpg");
// 2.2 Rotate the bitmap to be the same as display, if need.
... Add some bitmap rotate code
// 2.3 Size of rotated bitmap
int bitWidth = bitmap.getWidth();
int bitHeight = bitmap.getHeight();
// 3. Size of camera preview on screen
int preWidth = preview.getWidth();
int preHeight = preview.getHeight();
// 4. Scale it.
// Assume you draw Rect as "canvas.drawRect(60, 50, 210, 297, paint);" command
int startx = 60 * bitWidth / preWidth;
int starty = 50 * bitHeight / preHeight;
int endx = 210 * bitWidth / preWidth;
int endy = 297 * bitHeight / preHeight;
// 5. Crop image
Bitmap blueArea = Bitmap.createBitmap(bitmap, startx, starty, endx, endy);
// 6. Save Crop bitmap to file
This will work for you: How to programmatically take a screenshot in Android?
Make sure that the view (v1 in the code sample's case) passed in Bitmap.createBitmap(v1.getDrawingCache()) is a viewgroup that contains the image you want ot send to the second activity
Edit:
I don't think your intended flow is feasible. As far as I know, camera intents don't take arguments allowing to draw such a rectangle (I could be wrong though).
Instead, I suggest you take a picture, and then edit it with a library such as this one (https://github.com/ArthurHub/Android-Image-Cropper) or programatically as suggested above.
The app I'm creating requires a number of images to be pulled from our server, and displayed on a page. The user can go into several different categories, and each will have their own images. The problem is after going to 2-3 categories (depending on how many images are in those categories) in a row, the app has no more memory and cannot display the Bitmaps without crashing.
What I'd like to be able to do is clear the memory every time the user goes to a new category so that the old category's images won't be stored in memory anymore, freeing up space for the relevant category's images. I'm not sure if this is a good way to do it, or even how to do it if it was.
If anyone has a better solution let me know. One idea that was thrown around was loading only ~20 images at once, and waiting until the user scrolls to the bottom before loading more, however since our customers are paying to have their images on the app, that would cause less traffic to certain images, so this is not the ideal solution. However it's not out of the question.
Here is the code I'm using to load the images:
EDIT: My Mistake I posted the wrong code, this is the real code I'm using:
#SuppressWarnings("deprecation")
public Drawable loadImageFromWebOperations(String url, String imagePath) {
try {
if(Global.couponBitmaps.get(imagePath) != null){
scaledHeight = Global.couponBitmaps.get(imagePath).getHeight();
return new BitmapDrawable(getResources(), Global.couponBitmaps.get(imagePath));
}
Drawable d = null;
File f = new File(getBaseContext().getFilesDir().getPath().toString() + "/" + imagePath + ".png");
if (f.exists()) {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
int scaledWidth = 0;
try {
display.getSize(size);
scaledWidth = size.x;
} catch (java.lang.NoSuchMethodError ignore) {
scaledWidth = display.getWidth();
}
Bitmap bitmap = null;
BitmapScaler scaler = new BitmapScaler(f, scaledWidth);
bitmap = scaler.getScaled();
scaledHeight = bitmap.getHeight();
d = new BitmapDrawable(getResources(), bitmap);
Global.couponBitmaps.put(imagePath, bitmap);
} else {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
int scaledWidth = 0;
try {
display.getSize(size);
scaledWidth = size.x;
} catch (java.lang.NoSuchMethodError ignore) {
scaledWidth = display.getWidth();
}
Bitmap bitmap = BitmapFactory.decodeStream((InputStream) new URL(url).getContent());
int height = bitmap.getHeight();
int width = bitmap.getWidth();
scaledHeight = (int) (((scaledWidth * 1.0) / width) * height);
f.getParentFile().mkdirs();
f.createNewFile();
OutputStream output = new FileOutputStream(f);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, output);
output.close();
bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, false);
d = new BitmapDrawable(getResources(), bitmap);
Global.couponBitmaps.put(imagePath, bitmap);
}
return d;
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (OutOfMemoryError e){
e.printStackTrace();
return null;
}
}
If anyone knows if there is a more efficient way of loading the images, or if there is a way to clear the memory before drawing them, it would be greatly appreciated, thank you.
Since you are loading your Bitmaps from a server, you should probably use an image loading library.
Powerful libraries are for example:
Picasso, by square
UniversalImageLoader, by nostra13
They allow you to do pretty much anything with your Bitmap and during loading. Chaching is also supported.
UniversalImageLoader is slightly more powerful, Picasso is easier to use, in my opinion.
Bitmaps in android are a bit tricky.. My first app which required a large number of images in a gridview - I ran into a lot of OOM problems as well.
I ended up using nostra13's "Universal Image Loader" as it seemed to be the best solution for what I needed. It has a lot of built in features such as disk cache, memory cache, bitmap size, thread pool size, image scaling, etc. There are working examples too. :)
Nostra13 Universal Image Loader
There are a few things to keep in mind:
Recycle your bitmaps before displaying the next one else they will
pile up in memory and you'll get OOM
If using Universal Image Loader, make sure you use .bitmapConfig(Bitmap.Config.RGB_565) as it uses the least amount of memory per image.
If you plan on displaying a lot of images in a gridview or listview, the approach I used is to load two different images from your APIs, one being extremely small (100x100 ish) for thumbnail view, and the other being the full size image. This way you wont run out of memory when showing the thumbnails. Then only when the user clicks a thumbnail, will it load the the full size image for that position.
Hopefully this helps. :)
Every time you create new Drawable and BitmapDrawable use one Drawable and refresh image on it.
I make use of the following code to set my static images as wallpaper from my android app.. The image dimensions are like 425*700, 280*180, 600*400 etc., so the image dimensions are not the same.
try {
WallpaperManager myWallpaperManager = WallpaperManager
.getInstance(context);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int fullWidth = size.x;
int fullHeight = size.y;
// int fullWidth = wManager.getDesiredMinimumWidth();
// int fullHeight = wManager.getDesiredMinimumHeight();
Log.d("Debug", Integer.toString(fullWidth));
Log.d("Debug", Integer.toString(fullHeight));
Bitmap bitmap = BitmapFactory.decodeStream(getResources()
.openRawResource(R.drawable.hello));
Bitmap bitmapResized = Bitmap.createScaledBitmap(bitmap, fullWidth,
fullHeight, true);
myWallpaperManager.suggestDesiredDimensions(
bitmapResized.getWidth(), bitmapResized.getHeight());
myWallpaperManager.setBitmap(bitmapResized);
} catch (IOException e) {
e.printStackTrace();
}
But the images are quite streched and doesn't look good after setting as a wallpaper in the phone.. What am I doing wrong?
I guess problem lies in the resources as you have already mentioned. For a good view/quality of wallpaper we have to use different resources of images as according to the resolution of your device, if you want to use your application of setting the wallpaper to be used by many devices without making any changes(an apk). The crux is, you need a better quality image matching the resolution of your device. Hope it helps.
Edit: The distortion is again because you are resizing your image for covering full screen size. I guess if you do not resize it, it might work, though I havent use it till now.
EDIT:
After playing around with it for a few hours, I came to believe that the problem is in the image quality. For example, to first image is how it came from the camera. Decoder can't read it. The second image is turned into B/W with adjusted contrast and the decoder reads it great.
Since the demo app that came with zxing is able to read the fist image off the monitor in a few seconds, I think the problem might be in some setting deep within the zxing library. It doesn't wait long enough to process the image, but spits out NotFound almost instantly.
I'm making a simple QR-reader app. Here's a screenshot.
The top black area is a surfaceview, that shows frames from the camera. It works fine, only you can't see it in the screenshot.
Then, when I press the button, a bitmap is taken from that surfaceview, placed on an ImageView below and is attempted to be read by the zxing library.
Yet it will give out a NotFoundException. :/
**10-17 19:53:15.382: WARN/System.err(2238): com.google.zxing.NotFoundException
10-17 19:53:15.382: WARN/dalvikvm(2238): getStackTrace() called but no trace available**
On the other hand, if I crop the qr image from this screenshot, place it into the imageview ( instead of a camera feed ) and try to decode it, it works fine. Therefor the QR image itself and its quality are OK... but then why doesn't it decode in the first scenario?
Thanks!
public void dec(View v)
{
ImageView ivCam2 = (ImageView)findViewById(R.id.imageView2);
ivCam2.setImageBitmap(bm);
BitmapDrawable drawable = (BitmapDrawable) ivCam2.getDrawable();
Bitmap bMap = drawable.getBitmap();
TextView textv = (TextView) findViewById(R.id.mytext);
LuminanceSource source = new RGBLuminanceSource(bMap);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Reader reader = new MultiFormatReader();
try {
Result result = reader.decode(bitmap);
Global.text = result.getText();
byte[] rawBytes = result.getRawBytes();
BarcodeFormat format = result.getBarcodeFormat();
ResultPoint[] points = result.getResultPoints();
textv.setText(Global.text);
} catch (NotFoundException e) {
textv.setText("NotFoundException");
} catch (ChecksumException e) {
textv.setText("ChecksumException");
} catch (FormatException e) {
textv.setText("FormatException");
}
}
how the bitmap is created:
#Override
public void surfaceCreated(SurfaceHolder holder)
{
try
{
this.camera = Camera.open();
this.camera.setPreviewDisplay(this.holder);
this.camera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] _data, Camera _camera) {
Camera.Parameters params = _camera.getParameters();
int w = params.getPreviewSize().width;
int h = params.getPreviewSize().height;
int format = params.getPreviewFormat();
YuvImage image = new YuvImage(_data, format, w, h, null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
Rect area = new Rect(0, 0, w, h);
image.compressToJpeg(area, 50, out);
bm = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.size());
}
});
}
catch(IOException ioe)
{
ioe.printStackTrace(System.out);
}
}
I wrote this code. Returning quickly isn't a problem. Decoding is very fast on a mobile, and very very fast on a desktop.
The general answer to this type of question is that some images just aren't going to decode. That's life -- the heuristics don't always get it right. But I don't think that is the problem here.
QR codes don't decode without a minimal white "quiet zone" around them. The image beyond its borders is considered white for this purpose. But in your raw camera image, there's little border around the code and it's not all considered white by the binarizer, I'd bet.
Still, there's more you can do. Set the TRY_HARDER hint to the decoder, for one, to have it spend a lot more CPU to try to decode. You can also try a different Binarizer implementation than the default HybridBinarizer.
(The rest looks just fine. I assume that RGBLuminanceSource is getting data in the format it expects; it ought to from Bitmap)
See this: http://zxing.org/w/docs/javadoc/com/google/zxing/NotFoundException.html The exception means that a barcode wasn't found in the image. My suggestion would be to use your work around that works instead of trying to decode the un-cropped image.