I have a webservice running and ready to consume images produced by my Android tablet camera (Samsumg Galaxy TAB 10.1).
It works perfectly when consuming images taken at 1024x768 resolution (0.8M). However, when using the tablet's highest resolution (2048x1536, or 3.2M), the image saved simply does not work. It saves a broken image file with 0kb size.
This is the code related to the image-saving in the webservice:
public static void saveFile(final InputStream file, final String filePath) throws IOException {
OutputStream out = new FileOutputStream(new File(filePath.trim()));
int read = 0;
byte[] bytes = new byte[2048];
while ((read = file.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
file.close();
out.flush();
out.close();
}
I've already tried increasing the byte array size, but it didn't help.
The file variable is produced like this:
final InputStream image = data.getImage().getDataHandler().getInputStream();
Where data is a object consumed via a multipart request made by the webservice to Android, like this.
Any ideas?
Related
I'm testing different ways to store a jpg file in java and using a ByteArrayInputStream from a buffered image always results in a smaller file size. Is there anyway around this?
So for the whole picture, I'm currently trying to write a client-server image storing program(with eventual editing capabilities, think adobe lightroom). Uploading to the server from the client is no problem, just use Files.readAllBytes(currentFile.toPath()); and vice-versa when downloading to the client from the server, since it's being stored as a file.
The problem is what to do when I want to upload the same image I received(Assuming the image is edited and wanted to be reuploaded to server). I don't have a file created from it so I can't use the readAllBytes functions, they're only stored as an Image Object or BufferedImage. When I write that to a ByteArrayInputStream and get the size of the byte[] array to send back to the server, it's always smaller than the originals.
As a last resort I can make this into an export option so you have to download an image from the server onto the computer before editing, but it would make workflow less efficient.
currentFile = fileChooser.showOpenDialog(window);
try{
currentImage = new Image(currentFile.toURI().toString());
SelectedImageView.setImage(currentImage);
MainImageLayout.setLeft(SelectedImageView);
System.out.println("Original file length "+currentFile.length());
try {
BufferedImage bImage = ImageIO.read(currentFile);
byte[] fileContent = Files.readAllBytes(currentFile.toPath());
System.out.println("bytes from fileContent " +fileContent.length);
ByteArrayOutputStream tmp = new ByteArrayOutputStream();
ImageIO.write(bImage, "jpg", tmp);
tmp.flush();
byte[] imageBytes = tmp.toByteArray();
tmp.close();
long length = imageBytes.length;
System.out.println("length of bytearraystream " + length);
Printed Results:
Original file length 196874
bytes from fileContent 196874
length of bytearraystream 117010
I have a java web application, where users can download images
The way i coded the download is using IOUtils.copy to the response stream
But downloading a 4mb image takes around 10 sec and its happening really slow.
It seems like the server is sending chunk at a time.
this is the way I am writing the image to the output stream:
OutputStream out = response.getOutputStream();
FileInputStream stream = new FileInputStream(path);
IOUtils.copy(stream, out);
out.flush();
out.close();
Is there a faster way to do this?
UPDATE
following code using 1MB buffer and copyLarge didn't make any change.
FileInputStream stream = new FileInputStream(path);
byte[] buffer = new byte[1024 * 1024];
IOUtils.copyLarge(stream, out,buffer );
Try copyLarge:
public static long copyLarge(InputStream input,
OutputStream output,
byte[] buffer) throws IOException
Use buffer size about 1Mb
I am converting an Image into byte[] using following code.
public static byte[] extractBytes (String ImageName) throws IOException {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
BufferedImage img=ImageIO.read(new File(ImageName));
ImageIO.write(img, "jpg", baos);
return baos.toByteArray();
}
Now when I am testing my code:
public static void main(String[] args) throws IOException {
String filepath = "image_old.jpg";
File outp=new File(filepath);
System.out.println("Size of original image="+outp.length());
byte[] data = extractBytes(filepath);
System.out.println("size of byte[] data="+data.length);
BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));
//converting the byte[] array into image again
File outputfile = new File("image_new.jpg");
ImageIO.write(img, "jpeg", outputfile);
System.out.println("size of converted image="+outputfile.length());
}
I am getting very strange results:
Size of original image=78620
size of byte[] data=20280
size of converted image=20244
After converting image into byte[], its size getting decreased by around 1/4th and also when I am converting byte[] back to image its size alters.But output image is successfully getting created in the desired location. I can see the slight difference in quality of the original image and new image after doing 500-600 % zoom in. New image is little blurred after zoom in.
Here is the image on which I am doing the testing http://pbrd.co/1BrOVbf
Please explain the reason of this change in size and also I want to know any method to get the same size after this.
The image you have is compressed with maximum quality setting ("100%" or 1.0 in ImageIO terms). JPEG compression isn't very effective at such high settings, and is thus quite a bit larger than usual. When using ImageIO.write(..., "JPEG", ...) the default quality setting will be used. This default is 0.75 (the exact meaning of such a value is encoder dependent though, and isn't exact science), and thus lower quality, resulting in a smaller file size.
(Another likely cause for such a significant decrease in file size between the original and the re-compressed image, is the removal of meta data. When reading using ImageIO.read(file) you are effectively stripping away any meta data in the JPEG file, like XMP, Exif or ICC profiles. In extreme cases (yes, I'm talking mainly about Photoshop here ;-)) this meta data can take up more space than the image data itself (ie. megabytes of meta data is possible). This is however, not the case for your file.)
As you can see from the second re-compression (from byte[] to final output file), the output is just slightly smaller than the input. This is because the quality setting (unspecified, so still using default) will be the same in both cases (also, any metadata would also be lost in this step, so not adding to the file size). The minor difference is likely due to some small losses (rounding errors etc) in the JPEG decompression/re-compression.
While slightly counter-intuitive, the least data-loss (in terms of change from the original image, not in file size) when re-compression a JPEG, is always achieved by re-compression with the same quality setting (using the exact same tables should be virtually lossless, but small rounding errors might still occur) as the original. Increasing the quality setting will make the file output larger, but the quality will actually degrade.
The only way to be 100% sure to not lose any data or image quality, is by not decoding/encoding the image in the first place, but rather just copy the file byte by byte, for instance like this:
File in = ...;
File out = ...;
InputStream input = new FileInputStream(in);
try {
OutputStream output = new FileOutputStream(out);
try {
copy(input, output);
}
finally {
output.close();
}
}
finally {
input.close();
}
And the copy method:
public void copy(final InputStream in, final OutputStream out) {
byte[] buffer = new byte[1024];
int count;
while ((count = in.read(buffer)) != -1) {
out.write(buffer, 0, count);
}
// Flush out stream, to write any remaining buffered data
out.flush();
}
When you call ImageIO.write(img, "jpeg", outputfile); the ImageIO library writes a jpeg image, using its own compression parameters. The output image appears to be more compressed than the input image. You can adjust the level of compression by changing the parameter in the call to jpegParams.setCompressionQuality below. The resulting file may be bigger or smaller than the original depending on the relative compression levels in each.
public static ImageWriter getImageWriter() throws IOException {
IIORegistry registry = IIORegistry.getDefaultInstance();
Iterator<ImageWriterSpi> services = registry.getServiceProviders(ImageWriterSpi.class, (provider) -> {
if (provider instanceof ImageWriterSpi) {
return Arrays.stream(((ImageWriterSpi) provider).getFormatNames()).anyMatch(formatName -> formatName.equalsIgnoreCase("JPEG"));
}
return false;
}, true);
ImageWriterSpi writerSpi = services.next();
ImageWriter writer = writerSpi.createWriterInstance();
return writer;
}
public static void main(String[] args) throws IOException {
String filepath = "old.jpg";
File outp = new File(filepath);
System.out.println("Size of original image=" + outp.length());
byte[] data = extractBytes(filepath);
System.out.println("size of byte[] data=" + data.length);
BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));
File outputfile = new File("new.jpg");
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(1f);
ImageWriter writer = getImageWriter();
outputfile.delete();
try (final ImageOutputStream stream = createImageOutputStream(outputfile)) {
writer.setOutput(stream);
try {
writer.write(null, new IIOImage(img, null, null), jpegParams);
} finally {
writer.dispose();
stream.flush();
}
}
System.out.println("size of converted image=" + outputfile.length());
}
This solution is adapted from the answer by JeanValjean given here Setting jpg compression level with ImageIO in Java
I know how to display local images in J2me. How can I display an online image? The following code (the image URL below is just for demo purposes) does not yield anything.
Image logo = Image.createImage("http://whatever.com/img/whatever.png");
Thanks
You need to load the image manually via a HttpConnection
Use this method to load the image:
public Image loadImage(String url) throws IOException {
HttpConnection hpc = null;
DataInputStream dis = null;
try {
hpc = (HttpConnection) Connector.open(url);
int length = (int) hpc.getLength();
byte[] data = new byte[length];
dis = new DataInputStream(hpc.openInputStream());
dis.readFully(data);
return Image.createImage(data, 0, data.length);
} finally {
if (hpc != null)
hpc.close();
if (dis != null)
dis.close();
}
}
See also this tutorial
Your first port of call for questions like this should be the MIDP 2.0 Javadocs.
There you will see that createImage has an overload which accepts an InputStream; this will do what you need.
Alternatively, you can download the entire image into a byte array and use yet another alternative form of createImage.
I have a BufferedImage object of a jpeg which needs to be streamed as servlet response.
The existing code streams the jpeg using JPEGImageEncoder which looks like this :
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(resp.getOutputStream());
resp.reset();
resp.setContentType("image/jpg");
resp.setHeader("Content-disposition", "inline;filename=xyz.jpg");
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(image);
param.setQuality(jpegQuality, false);
encoder.setJPEGEncodeParam(param);
encoder.encode(image);
I have noticed that this is resulting in the file size of the streamed jpeg to be tripled , unable to figure why.So I have tried using ImageIO to stream the jpeg
ImageIO.write(image, "jpg", out);
This works just fine, I am unable to decide why my predecessor has gone with the choice of JPEGImageEncoder and was wondering what issues would arise if I change to using ImageIO, I have compared both jpegs and couldn't really spot differences. Any thoughts?
To be clear, you've already a concrete JPEG image somewhere on disk or in database and you just need to send it unmodified to the client? There's then indeed absolutely no reason to use JPEGImageEncoder (and ImageIO).
Just stream it unmodified to the response body.
E.g.
File file = new File("/path/to/image.jpg");
response.setContentType("image/jpeg");
response.setHeader("Content-Length", String.valueOf(file.length()));
InputStream input = new FileInputStream(file);
OutputStream output = response.getOutputStream();
byte[] buffer = new byte[8192];
try {
for (int length = 0; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
}
finally {
try { input.close(); } catch (IOException ignore) {}
try { output.close(); } catch (IOException ignore) {}
}
You see the mistake of unnecessarily using JPEGImageEncoder (and ImageIO) to stream image files often back in code of starters who are ignorant about the nature of bits and bytes. Those tools are only useful if you want to convert between JPEG and a different image format, or want to manipulate (crop, skew, rotate, resize, etc) it.