Copying an image, loses Exif data - android

I am copying an image to a private directory like so:
FileChannel source = null;
FileChannel destination = null;
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
source.close();
destination.close();
..but when I insert it back in to Gallery, untouched, at a later time:
private void moveImageToGallery(Uri inUri) throws Exception {
MediaStore.Images.Media.insertImage(getContentResolver(), ImageUtil.loadFullBitmap(inUri.getPath()), null, null);
}
..it apparently loses its Exif data. The rotation no longer works. Is there some way I can copy an image file and not lose that data? Thanks for any suggestions.

FileChannel, here, seems to actually read the data, decode it, reencode it, then write it; thus losing the EXIF data. Copying a file (byte-by-byte) does not alter its content. The only thing that can happen before/after a copy is a file access change (remember: Android is based on Linux, Linux being an UNIX => rwx permissions (see chmod)), eventually denying the read or write of the file. So it is clear FileChannel does something unwanted.
This code will do the work:
InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(dest);
byte[] buf = new byte[1024]; int len;
while ((len = in.read(buf)) > 0)
out.write(buf, 0, len);
in.close();
out.close();

Related

Gmail file attachment download is failing with getContentResolver()

I'm writing a process that downloads/ copies a file attached to Gmail on to the SD card that my application can then read.
When a user clicks on the attachment my activity is fired and I use the following code to save to local storage;
InputStream in = getContentResolver().openInputStream( intent.getData() );
String ext = intent.getType().equals("text/xml") ? ".xml" : ".gpkg";
localFile = new File( TILE_DIRECTORY, "tmp/"+intent.getDataString().hashCode()+ext);
// If we haven't already cached the file, go get it..
if (!localFile.exists()) {
localFile.getParentFile().mkdirs();
FileIO.streamCopy(in, new BufferedOutputStream(new FileOutputStream(localFile)) );
}
The FileIO.streamCopy is simply;
public static void streamCopy(InputStream in, OutputStream out) throws IOException{
byte[] b = new byte[BUFFER];
int read;
while ((read = in.read(b)) != -1) {
out.write(b, 0, read);
}
out.close();
in.close();
}
This all works fine on a small file, but with a 6Mb attachment only 12Kb is ever getting written. I'm not even getting an error, the process just runs through very quickly and i'm left with a corrupt file.
This process is run in its own thread and is part of a larger app with a lot of fileIO, so there is no issue with permissions/ directories etc.
Is there something different I should be doing with the stream?
Incidentally, intent.getData() is
content://gmail-ls/mexxx#gmail.com/messages/6847/attachments/0.1/BEST/false
and intent.getType() is
application/octet-stream
Thanks
All work's fine with this code
InputStream in = new BufferedInputStream(
getContentResolver().openInputStream(intent.getData()) );
File dir = getExternalCacheDir();
File file = new File(dir, Utils.md5(uri.getPath()));
OutputStream out = new BufferedOutputStream( new FileOutputStream(file) );
streamCopy(in, out);

sending bmp usng sockets

I'm trying to send bmp image using socket. I have such code on android:
ByteArrayOutputStream stream = new ByteArrayOutputStream();
MainActivity.bmp.compress(Bitmap.CompressFormat.JPEG, 20,
stream);
byte[] byteArray = stream.toByteArray();
OutputStream os = echoSocket.getOutputStream();
os.write(byteArray,0,byteArray.length);
os.flush();
and on PC:
String q = SockIn.readLine();
File file = new File("filename.bmp");
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(q);
in bmp file I only get up to 401 bytes, which of course is corrupt bmp image. what am I doing wrong?
MODIFIED
modified PC side, now the code is:
InputStream in_ = clientSocket.getInputStream();
OutputStream out_ = new FileOutputStream("filename.bmp");
final byte[] buffer = new byte[1024];
int read = -1;
int i = 0;
while ((read = in_.read(buffer)) != -1) {
out_.write(buffer, 0, read);
System.out.println(i);
i++;
}
in_.close();
out_.close();
System.out.println("Done");
It never gets to last line( println("Done") ). when I close android program, it gets to last line and bmp opens succesfully
Your reading logic is completely off. You only use a readLine() once and then write that to file. The data that was written to the socket on the device side was binary. That means that trying to read it as if it were textual (as readLine() does) will return meaningless junk. The reason it's usually 401 bytes long is that readLine() will look for the first newline character combination and return everything up to that as a String. This is not what you want.
What you need is a loop that will read from the socket and write into the file as long as there is data in the socket. A standard copy loop should suffice here.
InputStream in = socket.getInputStream();
OutputStream out = new FileOutputStream(...);
final byte[] buffer = new byte[BUFFER_SIZE];
int read = -1;
while ((read = in.read(buffer)) != -1)
out.write(buffer, 0, read);
in.close();
out.close();
Note that the above code isn't tested but something to that effect should do the trick.
Why are you reading a String if you are sending a byte ?
Try those setp one by one only if the previous did not worked.
1. Read() and don't Readline() what you are writing
If you write a byte, read a byte
Byte obj = SockIn.read();
2. Encode your array before sending
Base64.encodeBase64String(byteArray);

Error while creating a new file in Android: FileNotFoundException: /test.png: open failed: EROFS (Read-only file system)

I have a png file in the raw folder. I get the inputStream using :
inputStream = getResources().openRawResource(R.raw.test);
I am trying to write this inputStream in a new file in an Android application. This is my code:
inputStream = getResources().openRawResource(R.raw.test);
File file = new File("/test.png");
outputStream = new FileOutputStream(file);
int read = 0;
byte[] bytes = new byte[1024*1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
outputStream.close();
inputStream.close();
When I run the application, I get the following error in the logcat:
java.io.FileNotFoundException: /test.png: open failed: EROFS (Read-only file system)
Basically I want to create a File object so that I can send this to my server.
Thank you.
You will not have access to the file-system root, which is what you're attempting to access. For your purposes, you can write to internal files new File("test.png"), which places the file in the application-internal storage -- better yet, access it explicitly using getFilesDir().
For truly temporary files, you might want to look into getCacheDir() -- should you forget to delete those temporary files, the system will reclaim the space when it runs out of room.
Here's my solution:
inputStream = getResources().openRawResource(R.raw.earth);
file = new File(Environment.getExternalStorageDirectory() + File.separator + "test.png");
file.createNewFile();
outputStream = new FileOutputStream(file);
int read = 0;
byte[] bytes = new byte[1024*1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
outputStream.close();
inputStream.close();

How can I set my android app background from a server?

I'm quite new to android programming and I have the following problem.
I want to be able to put an image om my server and then if I use my app it should use that image as a background.
From previous research I understand I cant save any files to the drawable file?
So is this even possible?
I am now this far:
URL url = new URL ("http://oranjelan.nl/oranjelan-bg.png");
InputStream input = url.openStream();
try {
String storagePath = Environment.getExternalStorageDirectory();
OutputStream output = new FileOutputStream (storagePath + "/oranjelangb.png");
try {
byte[] buffer = new byte[1000000];
int bytesRead = 0;
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0) {
output.write(buffer, 0, bytesRead);
}
} finally {
output.close();
}
} finally {
input.close();
}
But I get the following error
# String storagePath = Environment.getExternalStorageDirectory();
The compiller says cannot convert file to string.
It should be possible. Simple steps may include :-
1) Download image file from server, Store it to SDcard or assets folder.
links for step 1 >> link1 link2
2) Create a Bitmap from the file you downloaded.
3) Set that bitmap as a Background image.
You can pick steps and search on SO there should be lots of answers available.

Android: Faster way to read/write a ZipInputStream?

I am currently writing an application that reads a zip file in my assets folder which contains a bunch of images. I am using the ZipInputStream API to read the contents and then writing each file to my: Environment.getExternalStorageDirectory() directory. I have everything working but the first time the application is run writing the images to the storage directory is INCREDIBLY slow. It takes about about 5 minutes to write my images to disc. My code looks like this:
ZipEntry ze = null;
ZipInputStream zin = new ZipInputStream(getAssets().open("myFile.zip"));
String location = getExternalStorageDirectory().getAbsolutePath() + "/test/images/";
//Loop through the zip file
while ((ze = zin.getNextEntry()) != null) {
File f = new File(location + ze.getName());
//Doesn't exist? Create to avoid FileNotFoundException
if(f.exists()) {
f.createNewFile();
}
FileOutputStream fout = new FileOutputStream(f);
//Read contents and then write to file
for (c = zin.read(); c != -1; c = zin.read()) {
fout.write(c);
}
}
fout.close();
zin.close();
The process of reading the contents of the particular entry and then writing to it is VERY slow. I am assuming it is more to do with reading than writing. I've read that you can use a byte[] array buffer to speed up the process but this does not seem to work! I tried this but it only read part of the file...
FileOutputStream fout = new FileOutputStream(f);
byte[] buffer = new byte[(int)ze.getSize()];
//Read contents and then write to file
for (c = zin.read(buffer); c != -1; c = zin.read(buffer)) {
fout.write(c);
}
}
When I do that I only get about 600-800 bytes written. Is there a way to speed this up?? Have I implemented the buffer array incorrectly??
I found a much better solution which implements the BuffererdOutputStream API. My solution looks like this:
byte[] buffer = new byte[2048];
FileOutputStream fout = new FileOutputStream(f);
BufferedOutputStream bos = new BufferedOutputStream(fout, buffer.length);
int size;
while ((size = zin.read(buffer, 0, buffer.length)) != -1) {
bos.write(buffer, 0, size);
}
//Close up shop..
bos.flush();
bos.close();
fout.flush();
fout.close();
zin.closeEntry();
I managed to increase my load time from anywhere from an average of about 5 minutes to about 5 (depending on how many images are in the package). Hope this helps!
Try use http://commons.apache.org/io/
like:
InputStream in = new URL( "http://jakarta.apache.org" ).openStream();
try {
System.out.println( IOUtils.toString( in ) );
} finally {
IOUtils.closeQuietly(in);
}

Categories

Resources