BitmapFactory.decodeStream returns null reading local file - android-image

A quick summary of my problem: I am trying to read a local image file. If I include the file in my assets directory and treat it as an asset everything works fine. However, if I try to read it from the external sd card, BitmapFactory.decode stream returns null.
I've had the same results with both .jpeg and .png files.
This is how I obtain an InputStream from the asset file:
InputStream isa = context.getAssets().open("Boulder.jpg");
This is how I obtain an InputStream from the asset file:
File f = new File( "/mnt/extSdCard/Maps/Colorado/Boulder.jpg" );
InputStream isf = new BufferedInputStream( new FileInputStream( f.toString() ) );
In either case the InputStream is passed to this code: (If this code looks familiar, it was borrowed from an internet example)
this.decoder = BitmapRegionDecoder.newInstance(inputStream, false);
tmpOptions.inJustDecodeBounds = true;
Bitmap temp = BitmapFactory.decodeStream(inputStream, null, tmpOptions);
setSceneSize(tmpOptions.outWidth, tmpOptions.outHeight);
tmpOptions.inJustDecodeBounds = false;
tmpOptions.inSampleSize = (1<<downShift);
sampleBitmap = BitmapFactory.decodeStream(inputStream, null, tmpOptions);
Again, using the asset file derived InputStream, everything works fine. Conversely, with the sdCard file, outWidth and outHeight are both -1 after the first call and sampleBitmap is null after the second.
I'm really wrapped around the axle on with this problem and have spent a lot of time browsing this forum and experimenting with suggested solutions all to no avail. I also wrote some test code which opened both versions of the file, creating InputStreams as shown above, then read the contents of each stream and compared each byte and found them to be identical.
I've tried the code on different devices with the same results. I'm currently testing on a Galaxy Note II (Android 4.1.1) with the following version info in the AndroidManifest:
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16"/>
I need the ability to dynamically add files to the system so including everything as an asset is not an option. Any help would be greatly appreciated.

You can simple use
BitmapFactory.decodeFile(file.getAbsolutePath(), tmpOptions);
rather than
File f = new File( "/mnt/extSdCard/Maps/Colorado/Boulder.jpg" );
InputStream isf = new BufferedInputStream( new FileInputStream( f.toString() ) );
BitmapFactory.decodeStream(inputStream, null, tmpOptions)

Related

Read (audio) file from subfolder in AndroidAssets in Xamarin.Forms

I try to eneable audio in my Xamarin.Forms application. I want to have the audio files in a Subfolderof the Assetsfolder like this Assets/Subfolder/Audio.mp3
I have found a plugin SimpleAudioPlayer which provide an example.
The following code works like provided.
var player = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
player.Load("Audio.mp3");
Now I want to place the audio file in a subfolder and I tried to call
player.Load("Subfolder/Audio.mp3");
But I get an Java.IO.FileNotFoundException
I looked then into the implementation of the Load function and I fould the following code
public bool Load(string fileName)
{
player.Reset();
AssetFileDescriptor afd = Android.App.Application.Context.Assets.OpenFd(fileName);
player?.SetDataSource(afd.FileDescriptor, afd.StartOffset, afd.Length);
return PreparePlayer();
}
where the filename is pasted to the Assets.OpenFd() function. which returns an AndroidFileDesriptor
The documentation does not really provide any information from Microsoft and from the Android site.
My questions are
How can I receive the file from the subfolder in Android Assets?
What can I paste into the Assets.OpenFd() function (subfolders etc)?
I would appreciate any advice, since after a long time trying to resolve it I don't really have an idea.
According to the docs of the package, you won't be able to do just that because you have to use player.Load(GetStreamFromFile("mysound.wav")); where GetStreamFromFile is basically
Stream GetStreamFromFile(string filename)
{
var assembly = typeof(App).GetTypeInfo().Assembly;
var stream = assembly.GetManifestResourceStream("App." + filename);
// Obviously App in the line above should be replaced with your app
return stream;
}
And secondly you have to player.Load(GetStreamFromFile("Subfolder.mysound.wav")); where Subfolder is the name of your subfolder.

Flying-saucer/iText PDF not finding css file

I can generate a PDF using flying-saucer/iText. However, I can't figure out how to get the style sheet included in the PDF rendering.
I have used this flying-saucer/iText PDF in servlet not finding css file as reference.
There are multiple css files involved so I won't be able to use renderer.setDocument(doc, "http://example.com/something/page.html");
as a solution
I have implemented a something similar to what the asker used, but it's returning a Caused by: java.nio.file.InvalidPathException: Illegal char <:> at index 4: http://localhost:8080/proj/resources/css/custom1.css error
Here is my code
StringBuilder bui = new StringBuilder();
bui.append("<html><head><style>");
bui.append(readFile(path+"/resources/css/custom1.css", Charsets.UTF_8));
bui.append(readFile(path+"/resources/css/custom2.css", Charsets.UTF_8));
bui.append(readFile(path+"/resources/css/custom3.css", Charsets.UTF_8));
bui.append("</style></head>");
bui.append("<body><div><table>");
bui.append( xhtml_file );
bui.append("</table></div></body></html>");
InputStream stream = new ByteArrayInputStream(bui.toString().getBytes( StandardCharsets.UTF_8 ));
Document doc = tidy.parseDOM(stream, null);
File outputFile = new File(directory+ "FILENAME" +".pdf");
os = new FileOutputStream(outputFile);
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(doc, null);
renderer.layout();
renderer.createPDF(os, false);
renderer.finishPDF();
the path being passed is "http://localhost:8080"
if I enter "http://localhost:8080/resources/css/custom1.css" directly into the address bar, it shows the css file. I tried removing the 'path' but it's also not getting the css. What am I doing wrong?
Try the file:/// url protocol to point (with three slashes) pointing to the css file directly.

PHPExcel different behavior on different systems

I have PHPExcel on localhost and on server.
When I try to read xlsx file on localhost - all ok, but when I try to read same file on server - all cells with cyrillic words are empty.
All systems have same PHPExcel and PHP versions.
What could be the problem?
Thanks!
The problem with this file is that it was created by an application that doesn't recognise case-sensitivity in filenames.
The rels table indicates that the Shared Strings table (where all the text string values for the workbook are stored) is called sharedStrings.xml, but the actual file in the zip is called SharedStrings.xml. A file generated by MS Excel itself uses the correct case in the filename, so I'm guessing that this file was created using some third-party tool or library. MS Excel is clearly more forgiving about case-sensitivity in filenames, allowing it to read the zip regardless.
I can probably fix this by using
$zip->getFromIndex(
$zip->locateName('sharedStrings.xml', ZIPARCHIVE::FL_NOCASE);
);
rather than
$zip->getFromName('sharedStrings.xml');
but it will take me a couple of days to implement the fix
EDIT
Somewhere around line 310 of the /PHPExcel/Reader/Excel2007.php file is the getFromZipArchive() method that can be changed to read:
private function getFromZipArchive($archive, $fileName = '')
{
// Root-relative paths
if (strpos($fileName, '//') !== false) {
$fileName = substr($fileName, strpos($fileName, '//') + 1);
}
$fileName = PHPExcel_Shared_File::realpath($fileName);
// Apache POI fixes
$contents = $archive->getFromIndex(
$archive->locateName($fileName, ZIPARCHIVE::FL_NOCASE)
);
if ($contents === false) {
$contents = $archive->getFromIndex(
$archive->locateName(substr($fileName, 1), ZIPARCHIVE::FL_NOCASE)
);
}
return $contents;
}
and will then be able to access the Shared String file case-insensitively

HttpServletResponse PrintWriter to write an InputStream

I have a HttpServletResponse object and need to write a file contained in the jar. The following code segments do not work for me.
URI uri = <myclass>.class.getResource("/" + filename).toURI();
PrintWriter out = response.getWriter();
File f = new File(uri);
FileReader bis = new FileReader(f);
char[] buff = new char[1024];
int bytesRead;
// Simple read/write loop.
while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
out.write(buff, 0, bytesRead);
}
I know that this will work
InputStream inputStream = <myclass>.class.getResourceAsStream("/" + filename);
but I cannot get the PrintWriter out.write to write the inputStream.
Can anyone tell me how this can be done.
Thanks
Resolved using the following
InputStream inputStream = KCSSchemaController.class.getResourceAsStream("/" + schemaname);
OutputStream output = response.getOutputStream();
ByteStreams.copy(inputStream, output);
output.flush();
need to write a file contained in the jar.
That's not possible this way. You'd basically need to get an absolute disk file system path to the JAR file, extract it using JarInputStream (a JAR is basically a ZIP file which follows a specific folder structure and get special treatment by Java), edit/add the file in the extracted folder structure and then package it again using JarOutputStream. You'll possibly need to reload it afterwards using a (custom) ClassLoader if you need the changed JAR contents later during runtime.
This is however pretty complicated and makes no sense. As a completely different alternative, do not attempt to change the JAR, but just store the data somewhere else, e.g. on a fixed location on disk file system, or in a database, or as an user/system preference, etcetera. Which way to choose depends on the concrete functional requirement which is not clear from the question.

Why does Image.FromFile keep a file handle open sometimes?

I am doing a lot of image processing in GDI+ in .NET in an ASP.NET application.
I frequently find that Image.FromFile() is keeping a file handle open.
Why is this? What is the best way to open an image without the file handle being retained.
NB: I'm not doing anything stupid like keeping the Image object lying around - and even if I was I woudlnt expect the file handle to be kept active
I went through the same journey as a few other posters on this thread. Things I noted:
Using Image.FromFile does seem unpredictable on when it releases the file handle. Calling the Image.Dispose() did not release the file handle in all cases.
Using a FileStream and the Image.FromStream method works, and releases the handle on the file if you call Dispose() on the FileStream or wrap the whole thing in a Using {} statement as recommended by Kris. However if you then attempt to save the Image object to a stream, the Image.Save method throws an exception "A generic error occured in GDI+". Presumably something in the Save method wants to know about the originating file.
Steven's approach worked for me. I was able to delete the originating file with the Image object in memory. I was also able to save the Image to both a stream and a file (I needed to do both of these things). I was also able to save to a file with the same name as the originating file, something that is documented as not possible if you use the Image.FromFile method (I find this weird since surely this is the most likely use case, but hey.)
So to summarise, open your Image like this:
Image img = Image.FromStream(new MemoryStream(File.ReadAllBytes(path)));
You are then free to manipulate it (and the originating file) as you see fit.
I have had the same problem and resorted to reading the file using
return Image.FromStream(new MemoryStream(File.ReadAllBytes(fileName)));
Image.FromFile keeps the file handle open until the image is disposed. From the MSDN:
"The file remains locked until the Image is disposed."
Use Image.FromStream, and you won't have the problem.
using(var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
return Image.FromStream(fs);
}
Edit: (a year and a bit later)
The above code is dangerous as it is unpredictable, at some point in time (after closing the filestream) you may get the dreaded "A generic error occurred in GDI+". I would amend it to:
Image tmpImage;
Bitmap returnImage;
using(var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
tmpImage = Image.FromStream(fs);
returnImage = new Bitmap(tmpImage);
tmpImage.Dispose();
}
return returnImage;
Make sure you are Disposing properly.
using (Image.FromFile("path")) {}
The using expression is shorthand for
IDisposable obj;
try { }
finally
{
obj.Dispose();
}
#Rex in the case of Image.Dispose it calls GdipDisposeImage extern / native Win32 call in it's Dispose().
IDisposable is used as a mechanism to free unmanaged resources (Which file handles are)
I also tried all your tips (ReadAllBytes, FileStream=>FromStream=>newBitmap() to make a copy, etc.) and they all worked. However, I wondered, if you could find something shorter, and
using (Image temp = Image.FromFile(path))
{
return new Bitmap(temp);
}
appears to work, too, as it disposes the file handle as well as the original Image-object and creates a new Bitmap-object, that is independent from the original file and therefore can be saved to a stream or file without errors.
I would have to point my finger at the Garbage Collector. Leaving it around is not really the issue if you are at the mercy of Garbage Collection.
This guy had a similar complaint... and he found a workaround of using a FileStream object rather than loading directly from the file.
public static Image LoadImageFromFile(string fileName)
{
Image theImage = null;
fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
{
byte[] img;
img = new byte[fileStream.Length];
fileStream.Read(img, 0, img.Length);
fileStream.Close();
theImage = Image.FromStream(new MemoryStream(img));
img = null;
}
...
It seems like a complete hack...
As mentioned above the Microsoft work around causes a GDI+ error after several images have been loaded. The VB solution for me as mentioned above by Steven is
picTemp.Image = Image.FromStream(New System.IO.MemoryStream(My.Computer.FileSystem.ReadAllBytes(strFl)))
I just encountered the same problem, where I was trying to merge multiple, single-page TIFF files into one multipart TIFF image. I needed to use Image.Save() and 'Image.SaveAdd()`: https://msdn.microsoft.com/en-us/library/windows/desktop/ms533839%28v=vs.85%29.aspx
The solution in my case was to call ".Dispose()" for each of the images, as soon as I was done with them:
' Iterate through each single-page source .tiff file
Dim initialTiff As System.Drawing.Image = Nothing
For Each filePath As String In srcFilePaths
Using fs As System.IO.FileStream = File.Open(filePath, FileMode.Open, FileAccess.Read)
If initialTiff Is Nothing Then
' ... Save 1st page of multi-part .TIFF
initialTiff = Image.FromStream(fs)
encoderParams.Param(0) = New EncoderParameter(Encoder.Compression, EncoderValue.CompressionCCITT4)
encoderParams.Param(1) = New EncoderParameter(Encoder.SaveFlag, EncoderValue.MultiFrame)
initialTiff.Save(outputFilePath, encoderInfo, encoderParams)
Else
' ... Save subsequent pages
Dim newTiff As System.Drawing.Image = Image.FromStream(fs)
encoderParams = New EncoderParameters(2)
encoderParams.Param(0) = New EncoderParameter(Encoder.Compression, EncoderValue.CompressionCCITT4)
encoderParams.Param(1) = New EncoderParameter(Encoder.SaveFlag, EncoderValue.FrameDimensionPage)
initialTiff.SaveAdd(newTiff, encoderParams)
newTiff.Dispose()
End If
End Using
Next
' Make sure to close the file
initialTiff.Dispose()

Resources