I'm having quite a problem here.
When I read image and then save it, I get the same picture. But when I open the pixel value, the value of each pixel is slightly different(larger or smaller around 10 units).
Why did that pixel change? I only read the image, then save it, I don't make changes to the pixel. I create it with format RGB and save as a PNG with ByteArrayOutputStream method.
private void onCaptureImageResult(Intent data) {
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
File destination = new File(Environment.getExternalStorageDirectory(),
System.currentTimeMillis() + ".jpg");
FileOutputStream fo;
try {
destination.createNewFile();
fo = new FileOutputStream(destination);
fo.write(bytes.toByteArray());
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
ivImage.setImageBitmap(thumbnail);
}
private void onSelectFromGalleryResult(Intent data) {
Bitmap bm=null;
if (data != null) {
try {
bm = MediaStore.Images.Media.getBitmap(getApplicationContext().getContentResolver(), data.getData());
} catch (IOException e) {
e.printStackTrace();
}
}
bmp = bm;
}
public void save(View view){
operation= Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(),bmp.getConfig());
int size = bmp.getRowBytes() * bmp.getHeight();
bytearrayoutputstream = new ByteArrayOutputStream();
int[] gambarR = new int[size];
int[] gambarG = new int[size];
int[] gambarB = new int[size];
int[] gambarA = new int[size];
int k = 0;
for(int i=0; i<bmp.getWidth(); i++){
for(int j=0; j<bmp.getHeight(); j++){
int p = bmp.getPixel(i, j);
gambarR[k] = Color.red(p);
gambarG[k] = Color.green(p);
gambarB[k] = Color.blue(p);
gambarA[k] = Color.alpha(p);
k++;
}
}
int l = 0;
for(int i = 0; i<bmp.getWidth(); i++){
for(int j = 0; j<bmp.getHeight();j++){
operation.setPixel(i, j, Color.rgb(gambarR[l], gambarG[l], gambarB[l]));
l++;
}
}
String fileName = "_hasil.bmp";
Long tsLong = System.currentTimeMillis()/1000;
String ts = tsLong.toString();
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
File gambar = new File(baseDir + File.separator + ts + fileName);
try
{
gambar.createNewFile();
fileoutputstream = new FileOutputStream(gambar);
fileoutputstream.write(bytearrayoutputstream.toByteArray());
fileoutputstream.close();
}
catch (Exception e)
{
e.printStackTrace();
}
ivImage.setImageBitmap(operation);
}
I will show you the difference between the image. I only read and save, and don't change the pixel. I need the pixel didn't change when I save it back.
As others have noticed, much of the code that you posted appears to do not much useful, indicating that you either haven't read the documentation, or haven't thought through the problem thoroughly.
However, the specific problem appears to be that you are saving your image in a lossy compression format (JPEG), in this case, at 90% quality. "Lossy" means that by definition you will never get back exactly the bitmap that you had before compression. Even setting JPEG quality to 100% is unlikely to get you exactly the same bitmap as before compression.
If you want exactly the same values back when reading the file, you'll need to write a lossless format, such as PNG or BMP.
Related
I use this code to save an image, but it takes a long time. Sometimes it takes 10 second or more. I have decreased the bitmap size and it helps. But it also decreases the quality. How can I save bitmap in its original size without decrease in quality and fast?
String imageName = UUID.randomUUID().toString();
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root, "/removeBG");
if (!myDir.exists()) {
myDir.mkdirs();
}
String fname;
if (imgBackground.getDrawable() != null)
fname = imageName + ".jpg";
else
fname = imageName + ".png";
File file = new File(myDir, fname);
if (file.exists()) {
file.delete();
}
try {
file.createNewFile(); // if file already exists will do nothing
FileOutputStream out = new FileOutputStream(file);
bitmap = CropBitmapTransparency(bitmap);
bitmap = resizeBitmap(bitmap, MAX_SIZE, MAX_SIZE);
if (imgBackground.getDrawable() != null)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
else
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
MediaScannerConnection.scanFile(this, new String[]{file.toString()}, new String[]{file.getName()}, null);
I search this problem and find a soultion like this :
public static void create(OutputStream os,int cols,int rows,int r,int g,int b,int a) {
ImageInfo imi = new ImageInfo(cols, rows, 8, true); // 8 bits per channel, alpha
PngWriter png = new PngWriter(os, imi);
// just a hint to the coder to optimize compression+speed:
png.setFilterType(FilterType.FILTER_NONE);
ImageLineByte iline = new ImageLineByte (imi);
byte[] scanline = iline.getScanlineByte();// RGBA
for (int col = 0,pos=0; col < imi.cols; col++) {
scanline[pos++]=(byte) r;
scanline[pos++]=(byte) g;
scanline[pos++]=(byte) b;
scanline[pos++]=(byte) a;
}
for (int row = 0; row < png.imgInfo.rows; row++) {
png.writeRow(iline);
}
png.end();
}
I am too confused. I don't know how to use it.
MediaStore.Images.Media.insertImage (getContext ().getContentResolver (),
imgBitmap, nameFull.getText ().toString ().trim (),
"");
Try this using your own variable names. This worked for me
I want to design an app that generates a QR code and gives the user the possibility to save the generated image to their internal storage only. I successfully generate the bitmap and save it as .PNG image, but when I try to open it from the gallery it appears broken or corrupt.
Below is the code to generate the bitmap and display it on an ImageView(qrCode):
bitmap = encodeAsBitmap(value);
qrCode.setImageBitmap(bitmap);
Bitmap encodeAsBitmap(String str) throws WriterException {
BitMatrix result;
try {
result = new MultiFormatWriter().encode(str,
BarcodeFormat.QR_CODE, WIDTH, WIDTH, null);
} catch (IllegalArgumentException iae) {
// Unsupported format
return null;
}
int w = result.getWidth();
int h = result.getHeight();
int[] pixels = new int[w * h];
for (int y = 0; y < h; y++) {
int offset = y * w;
for (int x = 0; x < w; x++) {
pixels[offset + x] = result.get(x, y) ? getResources().getColor(R.color.colorBlack) :
getResources().getColor(R.color.colorWhite);
}
}
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, 500, 0, 0, w, h);
return bitmap;
}
It works perfectly up to this level. The user can then click a button in order to save this image to their device's internal storage, thanks to the below method:
public void onClickSaveCode(View view) {
String title = getResources().getString(R.string.saved_image_title_prepend) + stringDate;
String format = getResources().getString(R.string.saved_image_format);
String directory = getResources().getString(R.string.saved_image_directory);
// Method call to save image
saveImageToInternalStorage(bitmap, directory, title, format);
}
public boolean saveImageToInternalStorage(Bitmap bitmap, String directory, String title, String format) {
ContextWrapper contextWrapper = new ContextWrapper(getApplicationContext());
File imageDirectory = contextWrapper.getDir(directory, Context.MODE_WORLD_READABLE);
File path = new File(imageDirectory, title + format);
try {
FileOutputStream fos = new FileOutputStream(path);
// Use the compress method on the Bitmap object to write image to the OutputStream
bitmap.compress(Bitmap.CompressFormat.PNG, QUALITY, fos);
fos.close();
new SingleMediaScanner(this, path);
Toast.makeText(this, getString(R.string.save_success), Toast.LENGTH_LONG).show();
return true;
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, getString(R.string.save_failure), Toast.LENGTH_LONG).show();
return false;
}
}
And finally below is the MediaScannerConnection class to scan for all images saved to the device and display them in the gallery:
public class SingleMediaScanner implements MediaScannerConnectionClient {
private MediaScannerConnection mSC;
private File file;
public SingleMediaScanner(Context context, File f) {
file = f;
mSC = new MediaScannerConnection(context, this);
mSC.connect();
}
#Override
public void onMediaScannerConnected() {
mSC.scanFile(file.getAbsolutePath(), null);
}
#Override
public void onScanCompleted(String path, Uri uri) {
mSC.disconnect();
}
}
The images are saved, yet they appear in the gallery as broken files.
Any help will be greatly appreciated.
string path = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
string filePath = System.IO.Path.Combine(path, "compressed.png");
//Bitmap bmp = ((BitmapDrawable)imgV.Drawable).Bitmap;
Bitmap b = newBitmap;
FileStream ms = new FileStream(filePath, FileMode.Create);
//FileOutputStream fos = new FileOutputStream(filePath,true);
await b.CompressAsync(Bitmap.CompressFormat.Png, 100, ms);
ms.Close();
//ByteArrayOutputStream opstream = new ByteArrayOutputStream();
//b.Compress(Bitmap.CompressFormat.Png, 100, opstream);
//byte[] bytArray = opstream.ToByteArray();
Toast.MakeText(Application.Context, "Compressed : " , ToastLength.Short).Show();
imgCompress.SetImageBitmap(b);
I've created an app that loops through two bitmaps and store the pixel data into 2D arrays (compare1[][] & compare2[][]).
I believe my code is working to some extent. It looks like it saves the Bitmap but when I go to the gallery later its not there. Any ideas would be greatly appreciated; here is a sample of my code:
public void getPixels(int[][] compare2,int[][]compare1, int x)
{
Bitmap difference = Bitmap.createBitmap(width, height, Config.ARGB_8888);
for(int i = 0; i<width-1; i++)
{
for(int j=0; j<height-1; j++)
{
int mColor = BIT.get(x).getPixel(i, j);
int alpha = Color.alpha(mColor);
int red = Color.red(mColor);
int green = Color.green(mColor);
int blue = Color.blue(mColor);
int xAvg = ((red+green+blue)/3);
compare2[i][j] = xAvg;
if ((compare1[i][j] - compare2[i][j]) < 50)
{
difference.setPixel(i, j, -16777216);
//System.out.println("No Significant Change");
}
else
{
difference.setPixel(i, j, -1);
//System.out.println("Change");
}
}
}
try {
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
File file = new File(path,"Test.jpg");
fOut = new FileOutputStream(file);
difference.compress(Bitmap.CompressFormat.JPEG, 80, fOut);
fOut.flush();
fOut.close();
fOut = null;
} catch (Exception e) {
e.printStackTrace();
}
}
After you've saved the Image, you need to invoke the MediaScanner for the image to appear in the gallery:
Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory());
sendBroadcast(intent);
A detailed tutorial: Trigger Media Scanner.
Related question on SO:How update the android media database
I am using Zxing library to generate a barcode in my Android application
Intent intent = new Intent("com.google.zxing.client.android.ENCODE");
intent.putExtra("ENCODE_FORMAT", "UPC_A");
intent.putExtra("ENCODE_DATA", "55555555555");
startActivityForResult(intent,0);
Is there anyway to save the generated image in my application which is calling Zxing? I see that in my onActivityResult I get intent null.
Thanks in advance for your help
Take the views cache and save it in bitmap something like this
View myBarCodeView = view.getRootView()
//Else this might return null
myBarCodeView.setDrawingCacheEnabled(true)
//Save it in bitmap
Bitmap mBitmap = myBarCodeView.getDrawingCache()
OR
draw your own barcode or QR CODE
//Change the writers as per your need
private void generateQRCode(String data) {
com.google.zxing.Writer writer = new QRCodeWriter();
String finaldata =Uri.encode(data, "ISO-8859-1");
try {
BitMatrix bm = writer.encode(finaldata,BarcodeFormat.QR_CODE, 350, 350);
mBitmap = Bitmap.createBitmap(350, 350, Config.ARGB_8888);
for (int i = 0; i < 350; i++) {
for (int j = 0; j < 350; j++) {
mBitmap.setPixel(i, j, bm.get(i, j) ? Color.BLACK: Color.WHITE);
}
}
} catch (WriterException e) {
e.printStackTrace();
}
if (mBitmap != null) {
mImageView.setImageBitmap(mBitmap);
}
}
public void generateBarCode(String data){
com.google.zxing.Writer c9 = new Code128Writer();
try {
BitMatrix bm = c9.encode(data,BarcodeFormat.CODE_128,350, 350);
mBitmap = Bitmap.createBitmap(350, 350, Config.ARGB_8888);
for (int i = 0; i < 350; i++) {
for (int j = 0; j < 350; j++) {
mBitmap.setPixel(i, j, bm.get(i, j) ? Color.BLACK : Color.WHITE);
}
}
} catch (WriterException e) {
e.printStackTrace();
}
if (mBitmap != null) {
mImageView.setImageBitmap(mBitmap);
}
}
Once you get the bitmap image just save it
//create a file to write bitmap data
File f = new File(FilePath, FileName+".png");
f.createNewFile();
//Convert bitmap to byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageBitmap.compress(CompressFormat.PNG, 0, bos);
byte[] bytearray = bos.toByteArray();
//Write bytes in file
FileOutputStream fos = new FileOutputStream(f);
fos.write(bytearray);
fos.flush();
fos.close();
You can also check a small library from github that i had created to create Barcode or QR Code
GZxingEncoder Encoder = GZxingEncoder.getInstance();
Encoder.initalize(this);
//To generate bar code use this
Bitmap bitmap = Encoder.generateBarCode_general("some text")
It is not returned in the Intent right now. There's no way to get it. You could suggest a patch to make it be returned -- it is probably a couple days' work. Or try Girish's approach, which is just to embed the encoding directly.
To store the scanned image in ZXing, You have to override a method drawResultPoints in Class CaptureActivity.
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root);
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Image-"+ n +".jpg";
File file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
barcode.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
This will saved the scanned image in the root directory of SD card, you can customize it to save it in any particular folder you need. The image it will be storing is the scanned image which appears as a ghost image while you scan.
I'm trying to display images from android internal storage, I have only 4images(the images are screen shots taked before), I display these images in a GridView, it works, but it takes too much time, this is my code :
FileInputStream fis = null;
DataOutputStream outWriter = null;
ByteArrayOutputStream bufStream = null;
String imageFile;
int occurence;
for (int i=0; i<4; i++) {
try {
occurence = i+1;
imageFile = "preview"+occurence+".png";
fis = openFileInput(imageFile);
bufStream = new ByteArrayOutputStream();
outWriter = new DataOutputStream(bufStream);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int ch;
byte[] data = null;
try {
**while((ch = fis.read()) != -1)
outWriter.write(ch);**
outWriter.close();
data = bufStream.toByteArray();
bufStream.close();
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
favorPreviews.add(BitmapFactory.decodeByteArray(data, 0, data.length)) ;
}
As you can see, I'm using FileInputStream to read them, but that reads the files byte by byte in this loop :
while((ch = fis.read()) != -1)
outWriter.write(ch);
And it takes too much time, is anyone know a faster way to read these images?
To be faster is indicated to reduced the image size. It can be done using the Bitmap decodeFile (String pathName, BitmapFactory.Options opts)
Look this example:
public Bitmap getReducedBitmap(String path) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inSampleSize=4; // reduced the image to 1/4 of the orignal size
return BitmapFactory.decodeFile(path, opt);
}
Use BitmapFactory.decodeFile(String) instead. Then all of this file reading is handled for you.