How can I remove metadata from an image (JPG) without losing quality? - java

I already found this nearly similar question on Stackoverflow:
How can I remove metadata from a JPEG image in Java?
But when I use the Method described above, the saved image is being compressed. Is there any way to remove the metadata without compressing the image? Is there any library that I could use in my Java-Program?

Ok, I finaly found a solution by using Apache "commons-imaging":
https://svn.apache.org/repos/asf/commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/examples/WriteExifMetadataExample.java
public void removeExifMetadata(final File jpegImageFile, final File dst)
throws IOException, ImageReadException, ImageWriteException {
OutputStream os = null;
try {
os = new FileOutputStream(dst);
os = new BufferedOutputStream(os);
new ExifRewriter().removeExifMetadata(jpegImageFile, os);
} finally {
if (os != null) {
try {
os.close();
} catch (final IOException e) {
}
}
}
}

Related

Is it possible to load Executable once and keep calling it multiple times in Java?

I am working on prototype where in from my Java API I have to run an executable which in C#. There is code which inturn calls Matlab function.
Following is the java code to call the executable(an example)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
matProcessWrapper = new ExecWrapper.ExecWrapperBuilder
("C:\\Matlab\\HelloWorld\\bin\\Release\\netcoreapp3.1\\HelloWorld.exe")
.setErrorStream(errorStream)
.setOutputStream(outputStream)
.setTimeOutMilliSeconds(30*1000L)
.build();
try {
matProcessWrapper.executeProcessSync();
} catch (IOException e) {
e.printStackTrace();
}
The executable is loaded each time. is it possible to load this executable only once and then call its method again and again and once all the calling is done I can exit the model.
You could check if your process wrapper is already loaded or load it in your constructor.
public void execute() {
if (matProcessWrapper == null) {
loadMatProcessWrapper();
}
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream errorStream = new ByteArrayOutputStream()) {
matProcessWrapper.executeProcessSync();
} catch (IOException e) {
e.printStackTrace();
}
}
public void loadMatProcessWrapper() {
matProcessWrapper = new ExecWrapper.ExecWrapperBuilder
("C:\\Matlab\\HelloWorld\\bin\\Release\\netcoreapp3.1\\HelloWorld.exe")
.setErrorStream(errorStream)
.setOutputStream(outputStream)
.setTimeOutMilliSeconds(30 * 1000L)
.build();
}
Also don't forget to close your streams, I did this in my code snippet with try with resources.

Download Google Docs file from Google Drive with java

I am trying to download a file from Google Drive. Download of a common file (pdf, jpg) went without any problem. But I can't get it to download Google files. I am getting an empty file without type and with size 0. Do you have any idea of what might cause this?
public InputStream download(String id) throws CloudServiceException {
try {
File file = service.files()
.get(id)
.execute();
String link = file.getExportLinks().get("application/pdf");
HttpResponse resp = service.getRequestFactory()
.buildGetRequest(
new GenericUrl(link))
.execute();
return resp.getContent();
} catch (HttpResponseException e) {
throw CloudServiceExceptionTransformer.transform(e, e.getStatusCode());
} catch(IOException ex) {
throw new InternalException(ex);
}
}
You need to use Export method for downloading google docs or any google files
String fileId = "1ZdR3L3qP4Bkq8noWLJHSr_iBau0DNT4Kli4SxNc2YEo";
OutputStream outputStream = new ByteArrayOutputStream();
driveService.files().export(fileId, "application/pdf")
.executeMediaAndDownloadTo(outputStream);
You can try this:
URL url = new URL("http://www.gaertner-servatius.de/images/sinnfrage/kapitel-2/spacetime.gif");
InputStream inStream = url.openStream();
Files.copy(inStream, Paths.get("foobar.gif"), StandardCopyOption.REPLACE_EXISTING);
inStream.close();
Try this:
com.google.api.services.drive.Drive service;
static InputStream download(String id) {
if (service != null && id != null) try {
com.google.api.services.drive.model.File gFl =
service.files().get(id).setFields("downloadUrl").execute();
if (gFl != null){
return service.getRequestFactory()
.buildGetRequest(new GenericUrl(gFl.getDownloadUrl())).execute().getContent());
}
} catch (Exception e) { e.printStackTrace(); }
return null;
}
Good Luck
So the problem was in fact in building of a response. Google files have a size 0 and google media type was not recognized which resulted in this broken file.
Edit: Here is my working version. I removed the set size so that it downloads those 0 sized files.
ResponseEntity.BodyBuilder builder = ResponseEntity.status(HttpStatus.OK)
.header(HttpHeaders.CONTENT_DISPOSITION, encoding)
.contentType(MediaType.parseMediaType(resource.getMimeType()));
return builder.body(new InputStreamResource(resource.getContent()));

Java 7 retrieve and read local file using fileinput stream

How can i retrieve and read local file using fileinputstream using Java 7. Something like this but for a local file. With the new security settings, I cant get it to work
public static InputStream openReading(String file)
throws FileNotFoundException
{
try
{
PersistenceService pService = (PersistenceService) ServiceManager
.lookup(PersistenceService.class.getCanonicalName());
URL fileurl = new URL(getCode() + file);
FileContents fc= pService.get(fileurl);
fc.setMaxLength(10240000);
InputStream in= fc.getInputStream();
return stream;
}
catch (MalformedURLException m)
{
m.printStackTrace();
}
catch (FileNotFoundException f)
{
throw new FileNotFoundException(f.getMessage());
}
}
ExtendedService.openFile is the equivalent for opening a file. That gives read/write access. There is no option to ask for read-only!

java.io.FileNotFoundException when uploading a file from a JSP

I have coded a AJAX file upload feature in my application. It works perfectly when running it from my laptop. When I try the exact same file using the same app, but deployed on a jBoss server, I get the following exception:
2013-02-18 11:30:02,796 ERROR [STDERR] java.io.FileNotFoundException: C:\Users\MyUser\Desktop\TestFile.pdf (The system cannot find the file specified).
getFileData method:
private byte[] getFileData(File file) {
FileInputStream fileInputStream = null;
byte[] bytFileData = null;
try {
fileInputStream = new FileInputStream(file);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
if (fileInputStream != null) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] bytBuffer = new byte[1024];
try {
for (int readNum; (readNum = fileInputStream.read(bytBuffer)) != -1;) {
byteArrayOutputStream.write(bytBuffer, 0, readNum);
}
} catch (IOException e) {
e.printStackTrace();
}
bytFileData = byteArrayOutputStream.toByteArray();
}
return bytFileData;
}
Getting the file content in a variable (from the method above):
byte[] bytFileData = this.getFileData(file);
Making the file:
private boolean makeFile(File folderToMake, File fileToMake, byte[] bytFileData) {
Boolean booSuccess = false;
FileOutputStream fileOutputStream = null;
try {
if (!folderToMake.exists()) {
folderToMake.mkdirs();
}
if (!fileToMake.exists()) {
if (fileToMake.createNewFile() == true) {
booSuccess = true;
fileOutputStream = new FileOutputStream(fileToMake);
fileOutputStream.write(bytFileData);
fileOutputStream.flush();
fileOutputStream.close();
}
}
} catch (Exception e) {
e.printStackTrace();
booSuccess = false;
}
return booSuccess;
}
Any idea?
Thank you
Charles
It seems you're just passing the file path as part of the request to the server, not actually uploading the file, then attempting to use that file path to access the file.
That will work on your laptop because the code, when running locally, has access to your file system and will be able to locate the file. It won't work deployed on a server because it's an entirely separate machine, and as a result won't have access to your file system.
You'll need to modify your client-side (AJAX) code to actually upload the file, then modify your server-side code to use that uploaded file. Note that AJAX file uploads aren't generally possible - there are plugins for frameworks such as jQuery that provide this functionality using workarounds.
I'm not 100%, but I think proper AJAX file uploads may be possible using HTML5 features, but browser support for that is likely going to be pretty poor right now.

java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed

i am programming a soundboard from android.
the problem is that some sounds works, and some dont work.
here is the traceback that i get for the sounds that doesnt work
05-31 13:23:04.227 18440 18603 W System.err: java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
05-31 13:23:04.227 18440 18603 W System.err: at android.content.res.AssetManager.openAssetFd(Native Method)
05-31 13:23:04.227 18440 18603 W System.err: at android.content.res.AssetManager.openFd(AssetManager.java:331)
05-31 13:23:04.227 18440 18603 W System.err: at com.phonegap.AudioPlayer.startPlaying(AudioPlayer.java:201)
05-31 13:23:04.227 18440 18603 W System.err: at com.phonegap.AudioHandler.startPlayingAudio(AudioHandler.java:181)
05-31 13:23:04.235 18440 18603 W System.err: at com.phonegap.AudioHandler.execute(AudioHandler.java:64)
05-31 13:23:04.235 18440 18603 W System.err: at com.phonegap.api.PluginManager$1.run(PluginManager.java:86)
05-31 13:23:04.235 18440 18603 W System.err: at java.lang.Thread.run(Thread.java:1096)
any ideas?
You can disable asset compression for certain extensions like so:
android {
aaptOptions {
noCompress "pdf"
}
}
Source
People working with Tensorflow Lite file running into this issue,
Add the following lines to your Gradle file (android/app/build.gradle) inside the android{} block.
aaptOptions {
noCompress "tflite"
}
There is a limitations on opening compressed files in the assets folder. This is because uncompressed files can be directly memory mapped into the processes virtual address space, therefore avoiding needing the same amount of memory again for decompression.
Dealing with Asset Compression in Android Apps discusses some techniques in dealing with compressed files. You can trick aapt into not compressing the file by using an extension that is not compressed (e.g. mp3) or you can manually add them to the apk without compression instead of getting aapt to do the work.
You should disable compression for that file. Simply add:
aaptOptions {
noCompress "your-file-name"
}
To your app level build.gradle file inside android { }
This decidedly irritating situation comes about because when the .apk is built, some assets are compressed before storing them, whereas other are treated as already compressed (e.g. images, video) and are left alone. The latter group can be opened using openAssetFd, the former group can't - if you try, you get the "This file can not be opened as a file descriptor; it is probably compressed" error.
One option is to trick the build system into not compressing the assets (see the link in #nicstrong's answer), but this is fiddly. Better to try and work around the problem in a more predictable fashion.
The solution I cam up with uses the fact that while you can't open an AssetFileDescriptor for the asset, you can still open an InputStream. You can use this to copy the asset into the application's file cache, and then return a descriptor for that:
#Override
public AssetFileDescriptor openAssetFile(final Uri uri, final String mode) throws FileNotFoundException
{
final String assetPath = uri.getLastPathSegment(); // or whatever
try
{
final boolean canBeReadDirectlyFromAssets = ... // if your asset going to be compressed?
if (canBeReadDirectlyFromAssets)
{
return getContext().getAssets().openFd(assetPath);
}
else
{
final File cacheFile = new File(getContext().getCacheDir(), assetPath);
cacheFile.getParentFile().mkdirs();
copyToCacheFile(assetPath, cacheFile);
return new AssetFileDescriptor(ParcelFileDescriptor.open(cacheFile, MODE_READ_ONLY), 0, -1);
}
}
catch (FileNotFoundException ex)
{
throw ex;
}
catch (IOException ex)
{
throw new FileNotFoundException(ex.getMessage());
}
}
private void copyToCacheFile(final String assetPath, final File cacheFile) throws IOException
{
final InputStream inputStream = getContext().getAssets().open(assetPath, ACCESS_BUFFER);
try
{
final FileOutputStream fileOutputStream = new FileOutputStream(cacheFile, false);
try
{
//using Guava IO lib to copy the streams, but could also do it manually
ByteStreams.copy(inputStream, fileOutputStream);
}
finally
{
fileOutputStream.close();
}
}
finally
{
inputStream.close();
}
}
This does mean that your app will leave cache files lying about, but that's fine. It also doesn't attempt to re-use existing cache files, which you may or may not care about.
You should get this exception only if trying to open the FileDesriptor. For just reading the file you can go the way through the InputStream (AssetManager.open("filename.ext")). This worked for me.
If you need the file size in advance, you need the FileDescriptor (and therefore an uncompressed file) to call its getLength() method, otherwise you have to read the whole stream to determine its size.
This exception can be thrown by calling:
final AssetFileDescriptor afd = activity.getAssets().openFd(path);
I fixed the problem by saving the file in res/raw directory instead of assets folder, then get the AssetFileDescriptor this way:
final AssetFileDescriptor afd = activity.getResources().openRawResourceFd(rawId);
Then the FileNotFoundException is gone, and the file is not compressed anymore.
I have done a walk around, I use:
ParcelFileDescriptor mFileDescriptor = context.getAssets().openFd(file).getParcelFileDescriptor();
But that return: java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed.
Instead of this implementation I open the file directly using functions form ParcelFileDescriptor.
private void openRenderer(Context context,String fileName) throws IOException {
File file= FileUtils.fileFromAsset(context, fileName);
ParcelFileDescriptor parcelFileDescriptor = ParcelFileDescriptor.open(file,ParcelFileDescriptor.MODE_READ_WRITE);
mPdfRenderer = new PdfRenderer(parcelFileDescriptor);
}`
public class FileUtils {
private FileUtils() {
}
public static File fileFromAsset(Context context, String assetName) throws IOException {
File outFile = new File(context.getCacheDir(), assetName );
copy(context.getAssets().open(assetName), outFile);
return outFile;
}
public static void copy(InputStream inputStream, File output) throws IOException {
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(output);
boolean read = false;
byte[] bytes = new byte[1024];
int read1;
while((read1 = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read1);
}
} finally {
try {
if(inputStream != null) {
inputStream.close();
}
} finally {
if(outputStream != null) {
outputStream.close();
}
}
}
}
}
Just added the extension of my file like below in the build.gradle and solved my issue
android {
aaptOptions {
noCompress "tflite"
noCompress "txt"
noCompress "pdf"
}
}
If the file to be obtained from the assets folder is bigger than 1MB, then what has worked for me is to compress the file as a zip file, then unzip it before using it, and store it in the external storage uncompressed.
InputStream fileInputStream = getAssets().open("your_file.your_file_extension.zip");
unzipInputStream(fileInputStream, "your_folder_in_external_storage");
The unzipInputStream method I've used is this one:
public static void unzipInputStream(InputStream inputStream, String location)
{
try {
if ( !location.endsWith(File.separator) ) {
location += File.separator;
}
File f = new File(location);
if(!f.isDirectory()) {
f.mkdirs();
}
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(inputStream, BUFFER_SIZE));
try {
ZipEntry ze;
while ((ze = zin.getNextEntry()) != null) {
String path = location + ze.getName();
File unzipFile = new File(path);
if (ze.isDirectory()) {
if(!unzipFile.isDirectory()) {
unzipFile.mkdirs();
}
} else {
createParentDirectoriesIfMissing(unzipFile);
unzipFile(zin, unzipFile);
}
}
} finally {
zin.close();
}
} catch (Exception e) {
Log.e("", "Unzip exception", e);
}
}
private static void createParentDirectoriesIfMissing(File unzipFile)
{
File parentDir = unzipFile.getParentFile();
if ( null != parentDir ) {
if ( !parentDir.isDirectory() ) {
parentDir.mkdirs();
}
}
}
private static void unzipFile(ZipInputStream zin, File unzipFile) throws IOException
{
int size;
byte[] buffer = new byte[BUFFER_SIZE];
FileOutputStream out = new FileOutputStream(unzipFile, false);
BufferedOutputStream fout = new BufferedOutputStream(out, BUFFER_SIZE);
try {
while ( (size = zin.read(buffer, 0, BUFFER_SIZE)) != -1 ) {
fout.write(buffer, 0, size);
}
zin.closeEntry();
} finally {
fout.flush();
fout.close();
}
}
I just ran into the same problem, because the gnome-sound-recorder creates OGG files, which I can't play using the MediaPlayer. So I converted them to MP3 with ffmpeg and it worked. So I guess this is the easiest way.
ffmpeg -i youroggfile yournewfile.mp3
What I also noticed is that it does still show up with a question mark in the resources and that when I access it with R.raw.yournewfile I do not write the ".mp3" extension in the code.
I got the same issue, and I copy the file from res/raw to /data/data/your.app.pkg/cache folder, then everything go well :D
AssetFileDescriptor afd = null;
try {
File cache = new File(getCacheDir(), "my_data.dat");
if (!cache.exists()) {
copyInputStreamToFile(getResources().openRawResource(R.raw.my_data), cache);
}
afd = new AssetFileDescriptor(ParcelFileDescriptor.open(cache, ParcelFileDescriptor.MODE_READ_ONLY), 0, AssetFileDescriptor.UNKNOWN_LENGTH);
} catch (Exception e) {
e.printStackTrace();
}
private void copyInputStreamToFile(InputStream in, File file) {
BufferedOutputStream bfos = null;
try {
bfos = new BufferedOutputStream(new FileOutputStream(file));
byte[] buf = new byte[4096];
int len;
while ((len = in.read(buf)) != -1) {
bfos.write(buf, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bfos != null) {
bfos.close();
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In my case, it caused by resource.arsc is compressed. Rebuilding with uncompressed resource.arsc solve the problem.

Categories