I want to implement a behavior similar to Whatsapp, where when the user can upload an image. I tried opening the images in my app, but if the image is too large, I will have an out of memory error.
To solve this, I'm opening forwarding the images to be open in the phone's native image viewer using the platformRequest() method.
However, I want to know how is it Whatsapp modifies the phone's native image viewer to add a "Select" button, with which the user selects the image he wants to upload. How is that information sent back to the J2ME application and how is the image resized?
Edit:
I tried this in two different ways, both of which gave me the OOME.
At first, I tried the more direct method:
FileConnection fc = (FileConnection) Connector.open("file://localhost/" + currDirName + fileName);
if (!fc.exists()) {
throw new IOException("File does not exists");
}
InputStream fis = fc.openInputStream();
Image im = Image.createImage(fis);
fis.close();
When that didn't work, I tried a more "manual" approach, but that gave me an error as well.
FileConnection fc = (FileConnection) Connector.open("file://localhost/" + currDirName + fileName);
if (!fc.exists()) {
throw new IOException("File does not exists");
}
InputStream fis = fc.openInputStream();
ByteArrayOutputStream file = new ByteArrayOutputStream();
int c;
byte[] data = new byte[1024];
while ((c = fis.read(data)) != -1) {
file.write(data, 0, c);
}
byte[] fileData = null;
fileData = file.toByteArray();
fis.close();
fc.close();
file.close();
Image im = Image.createImage(fileData, 0, fileData.length);
When I call the createImage method, the out of memory error occurs in both cases.
This varies with the devices. An E72 gives me the error with 3MB images, while a newer device will give me the error with images larger than 10MBs.
MIDP 2 (JSR 118) does not have API for that, you need to find another way to handle big images.
As for WhatsApp, it looks like they do not rely on MIDP in supporting this functionality. If you check the Wikipedia page you'll note that they don't claim general Java ME as supported platform, but instead, list narrower platforms like Symbian, S40, Blackberry etc.
This most likely means that they implement "problematic features" like one you're asking about using platform-specific API of particular target devices, having essentially separate projects / releases for every platform listed.
If this feature is really necessary in your application, you likely will have to do something like this.
In this case, consider also encapsulating problematic features in a way to make it easier to switch just part of your source code when building it for different platforms. For example, Class.forName(String) can be used to load platform specific implementation depending on target platform.
//...
Image getImage(String resourceName) {
// ImageUtil is an interface with method getImage
ImageUtil imageUtil = (ImageUtil) Class.forName(
// get platform-specific implementation, eg
// "mypackage.platformspecific.s40.S40ImageUtil"
// "mypackage.platformspecific.bb.BBImageUtil"
// "mypackage.platformspecific.symbian.SymbialImageUtil"
"mypackage.platformspecific.s40.S40ImageUtil");
return imageUtil.getImage(resourceName);
}
//...
Related
In my web application I have an image uploading module. I want to check the uploaded file whether it's an image file or any other file. I am using Java in server side.
The image is read as BufferedImage in java and then I am writing it to disk with ImageIO.write()
How shall I check the BufferedImage, whether it's really an image or something else?
Any suggestions or links would be appreciated.
I'm assuming that you're running this in a servlet context. If it's affordable to check the content type based on just the file extension, then use ServletContext#getMimeType() to get the mime type (content type). Just check if it starts with image/.
String fileName = uploadedFile.getFileName();
String mimeType = getServletContext().getMimeType(fileName);
if (mimeType.startsWith("image/")) {
// It's an image.
}
The default mime types are definied in the web.xml of the servletcontainer in question. In for example Tomcat, it's located in /conf/web.xml. You can extend/override it in the /WEB-INF/web.xml of your webapp as follows:
<mime-mapping>
<extension>svg</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
But this doesn't prevent you from users who are fooling you by changing the file extension. If you'd like to cover this as well, then you can also determine the mime type based on the actual file content. If it's affordable to check for only BMP, GIF, JPG or PNG types (but not TIF, PSD, SVG, etc), then you can just feed it directly to ImageIO#read() and check if it doesn't throw an exception.
try (InputStream input = uploadedFile.getInputStream()) {
try {
ImageIO.read(input).toString();
// It's an image (only BMP, GIF, JPG and PNG are recognized).
} catch (Exception e) {
// It's not an image.
}
}
But if you'd like to cover more image types as well, then consider using a 3rd party library which does all the work by sniffing the file headers. For example JMimeMagic or Apache Tika which support both BMP, GIF, JPG, PNG, TIF and PSD (but not SVG). Apache Batik supports SVG. Below example uses JMimeMagic:
try (InputStream input = uploadedFile.getInputStream()) {
String mimeType = Magic.getMagicMatch(input, false).getMimeType();
if (mimeType.startsWith("image/")) {
// It's an image.
} else {
// It's not an image.
}
}
You could if necessary use combinations and outweigh the one and other.
That said, you don't necessarily need ImageIO#write() to save the uploaded image to disk. Just writing the obtained InputStream directly to a Path or any OutputStream like FileOutputStream the usual Java IO way is more than sufficient (see also Recommended way to save uploaded files in a servlet application):
try (InputStream input = uploadedFile.getInputStream()) {
Files.copy(input, new File(uploadFolder, fileName).toPath());
}
Unless you'd like to gather some image information like its dimensions and/or want to manipulate it (crop/resize/rotate/convert/etc) of course.
I used org.apache.commons.imaging.Imaging in my case. Below is a sample piece of code to check if an image is a jpeg image or not. It throws ImageReadException if uploaded file is not an image.
try {
//image is InputStream
byte[] byteArray = IOUtils.toByteArray(image);
ImageFormat mimeType = Imaging.guessFormat(byteArray);
if (mimeType == ImageFormats.JPEG) {
return;
} else {
// handle image of different format. Ex: PNG
}
} catch (ImageReadException e) {
//not an image
}
This is built into the JDK and simply requires a stream with support for
byte[] data = ;
InputStream is = new BufferedInputStream(new ByteArrayInputStream(data));
String mimeType = URLConnection.guessContentTypeFromStream(is);
//...close stream
Since Java SE 6 https://docs.oracle.com/javase/6/docs/api/java/net/URLConnection.html
Try using multipart file instead of BufferedImage
import org.apache.http.entity.ContentType;
...
public void processImage(MultipartFile file) {
if(!Arrays.asList(ContentType.IMAGE_JPEG.getMimeType(), ContentType.IMAGE_PNG.getMimeType(), ContentType.IMAGE_GIF.getMimeType()).contains(file.getContentType())) {
throw new IllegalStateException("File must be an Image");
}
}
I want to save an image to my Azure MobileService.
I have been looking around and found that you can use blob and azure storage. But instead of implementing this I would love if you could convert an image to string or stream that could be stored in a normal azure mobile service table.
I am creating images in my app as :
Canvas found = null;
try
{
found = FindParentOfType<Canvas>(ViewInteractionCanvas.canvas);
}
catch (Exception)
{
//MessageBox.Show(e.Message.ToString(), "ERROR", MessageBoxButton.OK);
found = ViewInteractionCanvas.canvas;
}
WriteableBitmap writeableBitmap = new WriteableBitmap(found, null);
var imageBrush = new ImageBrush
{
ImageSource = writeableBitmap,
Stretch = Stretch.None
};
writeableBitmap = null;
GC.Collect();
try
{
FindChildCanvas(found, imageBrush);
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString(), AppResources.ErrorSaving, MessageBoxButton.OK);
return false;
}
var fileStream = new MemoryStream();
writeableBitmap = new WriteableBitmap(found, null);
writeableBitmap.SaveJpeg(fileStream, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight, 100, 100);
fileStream.Seek(0, SeekOrigin.Begin);
string tempJPEG = "My.jpg";
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(tempJPEG))
{
myIsolatedStorage.DeleteFile(tempJPEG);
}
IsolatedStorageFileStream IsofileStream = myIsolatedStorage.CreateFile(tempJPEG);
/*
StreamResourceInfo sri = null;
Uri uri = new Uri(tempJPEG, UriKind.Relative);
sri = Application.GetResourceStream(uri);
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(sri.Stream);
WriteableBitmap wb = new WriteableBitmap(bitmap);
*/
// Encode WriteableBitmap object to a JPEG stream.
//Extensions.SaveJpeg(wb, IsofileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
writeableBitmap.SaveJpeg(IsofileStream, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight, 100, 100);
IsofileStream.Close();
}
dialogResult = MessageBox.Show(AppResources.ShieldCreator_SaveShield, AppResources.ShieldCreator_SaveShieldTitle, MessageBoxButton.OKCancel);
if (dialogResult == MessageBoxResult.OK)
{
MediaLibrary library = new MediaLibrary();
library.SavePictureToCameraRoll("picture", fileStream);
}
if (dialogResult == MessageBoxResult.Cancel)
{
}
fileStream.Close();
I was thinking that I could send the filestream or something like that? But Have not succeeded in doing so. Maybe this is completely impossible. But just wanted to investigate the possibility instead of starting to learn a new concept.
Hope somebody can help.
By default, Mobile Services data is backed by SQL Database. As long as you can find a way to create a proper data type in your table, you'd be able to do this. Just keep in mind: SQL Database databases are limited to 150GB, which will be eaten up faster if storing content in the database instance vs, say, blob storage with a URL to that blob being stored in your SQL table (which also costs significantly less than SQL Database service).
What you're talking about doing (storing the image data in your SQL database) is possible and not altogether difficult, but definitely not recommended. There are several issues including the size of the data and the inefficiency of storing data like this. At the end of the day though, if that's how you want to implement it, I have posts explaining how you can do so from an Android and an iOS app.:
Android: http://chrisrisner.com/Storing-Images-from-Android-in-Windows-Azure-Mobile-Services
iOS: http://chrisrisner.com/Storing-Images-from-iOS-in-Windows-Azure-Mobile-Services
Due to the data types supported by Mobile Services, you'd need to store the image data as strings (varchars in the database). Again, far from the most efficient but it'll work.
I use javamail to get message, when I get the message i have:
com.sun.mail.util.BASE64DecoderStream,
I know that is part of multipart message, in the source of message I have
Content-Type: image/png; name=index_01.png
Content-Transfer-Encoding: base64
How encode this message??
edit:
I have that code:
else if (mbp.getContent() instanceof BASE64DecoderStream){
InputStream is = null;
ByteArrayOutputStream os = null;
is = mbp.getInputStream();
os = new ByteArrayOutputStream(512);
int c = 0;
while ((c = is.read()) != -1) {
os.write(c);
}
System.out.println(os.toString());
}
And that code return strange string, for example:
Ř˙á?Exif??II*????????????˙ě?Ducky???????˙á)
com.sun.mail.util.BASE64DecoderStream is platform dependent. You cannot rely on that always being the type of class that handles base64 decoding.
Rather the javamail APIs already support decoding for you:
// part is instanceof javax.mail.Part
ByteArrayOutputStream bos = new ByteArrayOutputStream();
part.getDataHandler().writeTo(bos);
String decodedContent = bos.toString()
What are you expecting when you read the contents of an image part? The image is stored in the message in an encoded format, but JavaMail is decoding the data before returning the bytes to you. If you store the bytes in a file, you can display the image with many image viewing/editing applications. If you want to display them with your Java program, you'll need to convert the bytes to an appropriate Java Image object using (e.g.) APIs in the java.awt.image package.
That Sun's base 64 encoder is in the optional package and can be moved or renamed at any time without warning, also may be missing in alternative Java runtimes, also access to these packages may be disabled. It is much better not to rely on it.
I would say, use Base64 from Apache Commons instead, should do the same. Hope you can rebuild and fix the source code.
I'm using the below code (references from, http://www.java-tips.org/java-me-tips/midp/playing-video-on-j2me-devices.html). It fails at 'realize()', with the javax.microedition.media.MediaException, "Unable to create native player". What is the problem here?
I tried this using both Eclipse and Netbeans. Am I missing some "internet" permissions or using any incorrect encoding, the video is an external 'mpg' test-resource and does work fine when downloaded through a desktop browser.
public void run()
{
String url = "http://www.fileformat.info/format/mpeg/sample/05e7e78068f44f0ea748855ef33c9f4a/MELT.MPG";
//Append the GUI to a form
Form form = new Form("Video on java mobile!");
Display display = Display.getDisplay(this);
display.setCurrent(form);
try
{
HttpConnection conn = (HttpConnection)Connector.open(url,
Connector.READ_WRITE);
InputStream is = conn.openInputStream();
Player p = Manager.createPlayer(is,"video/mpeg");
//I tried the below, but that didn't work either
//Player p = Manager.createPlayer(url);
p.realize();
//Get the video controller
VideoControl video = (VideoControl) p.getControl("VideoControl");
if(video != null)
{
//Get a GUI to display the video
Item videoItem = (Item)video.initDisplayMode(
VideoControl.USE_GUI_PRIMITIVE, null);
form.append(videoItem);
}
//Start the video
p.prefetch();
p.start();
}
catch(Exception e)
{
form.append(url + " Error:" + e.getMessage());
}
}
I've just started with Java, Eclipse, Netbeans. Since, there similar samples found everywhere, I believe I'm missing something very basic. Can someone please help?
The problem here was the video file. Although my source video seemed "mpeg", it wasn't acceptable to the emulator. After searching through a bit, I found a converter and I manually converted some sample mp4 to "mpeg". It finally worked with the same emulator, after I tried to download and play these manually converted files.
One piece of advise if you are new J2ME/JavaME apps (like me), keep playing with the input data sources/formats and the emulators. Switching emulators or the input data-formats is an easy way to identify the not-so-evident problems.
My ImageHandler.ashx is not working when the webpart is calling it. any ideas on what is the correct way on calling or adding a handler in sharepoint? Thanks in advance
Here My ImageHandler.ashx code
byte[] buffer = (byte[])image.ImageData;
context.Response.ContentType = "image/jpeg";
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
In my webpart
imgcontrol.ImageUrl = "ImageHandler.aspx?id=1";
Check the Location where you have Deployed the ImageHandler.ashx. I have done similar thing in past and was able to get it working without any issues.
I deployed to _Layouts folder
imgcontrol.ImageUrl="_Layouts\x.ashx";
I assume that the code in your question is just a typo.
imgcontrol.ImageUrl = "ImageHandler.ashx?id=1";
this is a fragment from my own image handler that we use to load map pins in a sharepoint mapping webpart. We load the image, modify it, then return it.
Bitmap bmpPin = Bitmap.FromFile("myImageFile.jpg") as Bitmap
using (MemoryStream memStream = new MemoryStream())
{
this.m_Context.Response.ContentType = "image/png";
bmpPin.Save(memStream, ImageFormat.Png);
memStream.WriteTo(context.Response.OutputStream);
memStream.Close();
memStream.Dispose();
}
bmpPin.Dispose();