screencapture output format - android

I am trying to use the /system/bin/screencapture tool in Android in my program. I want to have the screenshot in a Bitmap object. (I know about the other methods, however, my program is using a SurfaceView and I cannot change that so none available on the internet I could find worked.)
I have found that using the -p option to encode it into a png file takes too much time. So I want to use the output without the -p option. However, I am unable to figure out what format that output uses. I have tried reading it into a byte array and using BitmapFactory.decodeByteArray() but that doesn't seem to work (method just returns null.)
TL;DR: What format does /system/bin/screencapture use when not using the -p option (or writing to a file name that ends with ".png")
Here's the relevant code:
Bitmap bitmap = null;
try {
Runtime.getRuntime().exec("/system/bin/screencap /storage/emulated/0/storage/screencap");
try {
Thread.sleep(45);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.v("findMe", "Finished writing file");
byte[] data = new byte[0];
FileInputStream fis = new FileInputStream("/system/bin/screencap");
while(fis.available() > 0){
data = append_to_byte_arr(data, (byte) fis.read());
}
Log.d("findMe", data.length + " is data.length");
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
} catch (IOException ioe) {
Log.e("findMe", "you failed", ioe);
return;
}
//...
private byte[] append_to_byte_arr(byte[] arr, byte item) {
byte[] temp = new byte[arr.length + 1];
System.arraycopy(arr, 0, temp, 0, arr.length);
temp[arr.length] = item;
return temp;
}
Thanks for the help.

Without the "-p" option the format depends about the filename extension: if it is ".png" the screenshot is automatically saved as PNG. Without any filename the screenshot is printed to "stdout". I tried many was and the best is to print out to "stdout" and then read directly the Bitmap pixels from there because the other methods involves the "screencap" to save to file and then your App should read it wasting "a lot of time" (near 1.5 seconds in both operations)

Related

Image size increased more after convert to Base64

I am using Compressor third party library for compress the captured images size its working fine and now size is showing KB's but when i convert this images to BASE64 file size becomes 6MB or more size showing my code is below can some one help me please what should i do for resolve this issue
code:
File file= new Compressor(this).compressToFile(f);
String base64File = getBase64StringFile(file);
// Converting File to Base64.encode String type using Method
public static String getBase64StringFile(File f) {
InputStream inputStream = null;
String encodedFile= "", lastVal;
try {
inputStream = new FileInputStream(f.getAbsolutePath());
byte[] buffer = new byte[10240];//specify the size to allow
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
Base64OutputStream output64 = new Base64OutputStream(output, Base64.DEFAULT);
while ((bytesRead = inputStream.read(buffer)) != -1) {
output64.write(buffer, 0, bytesRead);
}
output64.close();
encodedFile = output.toString();
}
catch (FileNotFoundException e1 ) {
e1.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
lastVal = encodedFile;
return lastVal;
}
You can resolve this issue using some other Compressor tools like FFMPEG.
Base64 always increase your file size
Base64 is often used on binary data that needs to be transmitted across a system that isn't really designed for binary. Depending on what you're doing, you may not even need to encode it. And per the wikipedia, on average, a file is expected to grow about 37% when you base64 encode it, which is almost exactly what your numbers are.

How to break a video into pieces using android?

I want java code to create partition of video of specific size.
e.g. Consider a video of size 20mb and I want peices of 5 mb each. so we get 4 parts.
I have used code below but it only creates .MP4 file it is not creating video file.
public static void divideFile(File f) {
int partCounter = 1;//I like to name parts from 001, 002, 003,
//you can change it to 0 if you want 000, 001,003
int sizeOfFiles = 1024 * 1024;// 1MB
byte[] buffer = new byte[sizeOfFiles];
String fileName = f.getName();
//try-with-resources to ensure closing stream
try (FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis)) {
int bytesAmount = 0;
while ((bytesAmount = bis.read(buffer)) > 0) {
//write each chunk of data into separate file with different number in name
String filePartName = String.format("%s.%03d", fileName, partCounter++);
File newFile = new File(f.getParent(), filePartName);
try (FileOutputStream out = new FileOutputStream(newFile)) {
out.write(buffer, 0, bytesAmount);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I think you want each part to be a playable video itself - in this case each part needs the correct metadata headers to allow a player to handle it properly.
Breaking the video up just by bytes will mean that metadata is not present or not correct in any of the chunks.
You can use ffmpeg to do this correctly with the following command (for mp4):
ffmpeg -I videoPath -ss startTime -t endTime -c copy outputVideoChunk.mp4
There are several ways to use ffmpeg within an Android app but one of the easiest is to use a well supported wrapper library like:
https://github.com/WritingMinds/ffmpeg-android-java

Android picture has red tint after decoding and pulling the .png file from the emulator to pc

I am transferring some data from a server ( java app ) to client ( android app ).
The data gets Base64 encoded, sent, received correct, decoded ( correct ? ) and stored to the device ( correct ? )
I am using android studio and an AVD to simulate it. I take the pictures via DDMS from the virtual device folder to my computers harddisk in order to take a look at them. Is maybe there the problem?
now in the following code sections the picture files get decoded and stored to the device.
Cant figure out where the mistake is.
Would be glad about any hint.
byte[] imageBackToByt = Base64.decode(parts[9], Base64.DEFAULT);
Bitmap bitmapImage = BitmapFactory.decodeByteArray(imageBackToByt, 0, imageBackToByt.length);
File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ ctx.getApplicationContext().getPackageName()
+ "/Files");
File imageFile = new File(mediaStorageDir.getPath() + File.separator + voReceived.name + ".png");
try {
FileOutputStream fos = new FileOutputStream(imageFile);
bitmapImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
fos.close();
} catch (FileNotFoundException e) {
Log.d(ctx.getString(R.string.SLDMP), "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(ctx.getString(R.string.SLDMP), "Error accessing file: " + e.getMessage());
}
This is how i encode it on the server in JAVA:
BufferedImage originalPicture = null;
ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
byte[] pictureInByte = null;
String pictureEncoded = null;
try {
// load the original picture from the filepath
originalPicture = ImageIO.read(picturFile);
// Convert the original picture from .png format to byte array (byte []) format
ImageIO.write(originalPicture, "jpg", byteArrayOS );
pictureInByte = byteArrayOS.toByteArray();
// Encode the byte array pictureInByte to String based on Base64 encoding
pictureEncoded = Base64.getEncoder().encodeToString(pictureInByte);
} catch (IOException e) {
e.printStackTrace();
// If picture failed to load / encode store string "PICTUREERROR" as an error code
pictureEncoded = "PICTUREERROR";
}
The server puts the bytes of the image file in a buffer and sends the contents of the base 64 encoded buffer to the client. Now on client side you should directly decode base 64 all bytes and write all the resulting bytes to file. In this way you have exactly the same file. All bytes are the same and file size would be equal too.
Instead you use BitmapFactory to construct a Bitmap and then compress it to PNG. That all makes no sense.
If you want to transfer a file then do not use BitmapFactory and Bitmap.
Having said that.. Mmmmm nice filter! The result is wonderfull!

Trouble downloading PNG images in Android

I am facing a problem downloading PNG images from my server to my Android app. The problem is specific to PNG images (JPG works fine), and the issue is that the downloaded files are corrupt images. I will explain in more details, below.
Scenario :
I need to download JPG and PNG images from my server, and display them to the user of the Android app.
Issue :
The JPG images get downloaded without an issue. But the downloaded PNG files are corrupt. I have double checked the source of the images at my server, and they are proper. Its only the downloaded PNG files, that are corrupt. So, the problem probably lies in the way I am downloading them in Android.
Code Sample :
URL imageURL;
File imageFile = null;
InputStream is = null;
FileOutputStream fos = null;
byte[] b = new byte[1024];
try {
// get the input stream and pass to file output stream
imageURL = new URL(image.getServerPath());
imageFile = new File(context.getExternalFilesDir(null), image.getLocalPath());
fos = new FileOutputStream(imageFile);
// get the input stream and pass to file output stream
is = imageURL.openConnection().getInputStream();
// also tried but gave same results :
// is = imageURL.openStream();
while(is.read(b) != -1)
fos.write(b);
} catch (FileNotFoundException e) {
} catch (MalformedURLException e) {
} catch (IOException e) {
} finally {
// close the streams
try {
if(fos != null)
fos.close();
if(is != null)
is.close();
} catch(IOException e){
}
}
Any pointers on how I can work on this, will be very appreciated.
Note :
Since this is happening in a service, there are no problems of doing this inside an AsyncTask.
The problem is here
while(is.read(b) != -1)
fos.write(b);
This is wrong, because in each iteration it will write the full buffer (1024 bytes) to the file. But the previous read could have read less bytes than than (almost surely on the last loop, unless the image lenght happens to be exactly a multiple of 1024). You should check how many bytes were read each time, and write that amount of bytes.
int bytesRead;
while( (bytesRead = is.read(b)) != -1)
fos.write(b,0,bytesRead );
Your error makes you write always files with sizes that are multiple of 1024 - which of course is not the case in general. Now, what happens when a image is saved with extra trailing bytes depends on the format and on the image reader. In some cases, it might work. Still, it's wrong.
BTW: never swallow exceptions - even if that's not the problem today, it might be tomorrow and you might spend hours finding the problem.

creating a copy of sdcard picture to another directory?

i am able to get the path of the picture i want to copy, and able to get the path from where i want it to be copy, but still cant find the way to copy them.
any suggestion?
private void copyPictureToFolder(String picturePath, String folderName)
throws IOException {
Log.d("debug", folderName);
Log.d("debug", picturePath);
try {
FileInputStream fileInputStream = new FileInputStream(picturePath);
FileOutputStream fileOutputStream = new FileOutputStream(folderName+"/");
int bufferSize;
byte[] bufffer = new byte[512];
while ((bufferSize = fileInputStream.read(bufffer)) > 0) {
fileOutputStream.write(bufffer, 0, bufferSize);
}
fileInputStream.close();
fileOutputStream.close();
} catch (Exception e) {
Log.d("disaster","didnt work");
}
}
thanks.
You should use Commons-IO to copy a file, we are in 2013 ! No one wants do that manually. If you really want then you should consider a few things :
first a loop that copies your file, at every iteration you copy buffer.length bytes. In you current code, you don't loop and copy 512 bytes of source image into dest (whatever the source image size is).
take care of last iteration and only copy what you read
your try/catch structure is not correct, you should add a finally close to always close your source and destination file. Look here for an example : what is the exact order of execution for try, catch and finally?
With IOUtils, it will give something like
try {
IOUtils.copy( source, dest );
} finally {
IOUtils.closeQuietly( source );
IOUtils.closeQuietly( dest );
}
and don't catch anything, it will be forwarded to the caller.

Categories

Resources