I am trying to write a simple server that uses sockets and reads images from disc when it receives http request from browser.
I am able to receive the request, read the image from disc and pass it to the browser (the browser then automatically downloads the image). However, when I try to open the downloaded image, it says:
Could not load image 'img.png'. Fatal error reading PNG image file: Not a PNG file
The same goes for all other types of extensions (jpg, jpeg, gif etc...)
Could you help me out and tell me what am I doing wrong? I suspect that there might be something wrong with the way I read the image or maybe some encoding has to be specified?
Reading the image from disc:
// read image and serve it back to the browser
public byte[] readImage(String path) {
File file = new File(FILE_PATH + path);
try {
BufferedImage image = ImageIO.read(file); // try reading the image first
// get DataBufferBytes from Raster
WritableRaster raster = image.getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
return data.getData();
} catch (IOException ex) {
// handle exception...
}
return ("Could not read image").getBytes();
}
Writing the data via socket:
OutputStream output = clientSocket.getOutputStream();
output.write(result);
In this case, the result contains the byte array produced by the readImage method.
EDIT: second try with reading the image as normal file
FileReader reader = new FileReader(file);
char buf[] = new char[8192];
int len;
StringBuilder s = new StringBuilder();
while ((len = reader.read(buf)) >= 0) {
s.append(buf, 0, len);
byte[] byteArray = s.toString().getBytes();
}
return s.toString().getBytes();
You may use ByteArrayOutputStream, like,
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", byteArrayOutputStream);
and then you can write to socket as,
outputStream.write(byteArrayOutputStream.toByteArray());
Related
The problem is that ImageIO.write does not recognize the raw format, so the file does not fill it. I tried the same code with png and it created it correctly. Is there some alternative to ImageIO.write or some other way to create a raw, raw byte file? Is there some conversion alternative for an image in Fid format?
Fid Image to raw
Buffered image to raw
Here I create the file I have indicated the address:
private void RAWCompression(Fid.Fiv imagen) throws IOException{
JFileChooser fileChooser = new JFileChooser(System.getProperty("java.library.path"));
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChooser.setSelectedFile(new File("HuellaRaw.raw"));
fileChooser.showSaveDialog(null);
File dir = fileChooser.getSelectedFile();
File file = new File(dir.getAbsolutePath() + "/" + "HuellaRaw.raw");
System.out.println(file);
//Create file
try {
file.createNewFile();
} catch (IOException ex) {
Logger.getLogger(Capture.class.getName()).log(Level.SEVERE, null, ex);
}
I send the image to buferrtd:
BufferedImage imagenBuffered = new BufferedImage(imagen.getWidth(), imagen.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
imagenBuffered.getRaster().setDataElements(0, 0, imagen.getWidth(), imagen.getHeight(), imagen.getData());
I fill the file and convert it to bytes:
//convert BufferedImage to byte
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(imagenBuffered, "raw", baos);
byte[] bytes = baos.toByteArray();
//FileUtils.writeByteArrayToFile(file, bytes);
try (FileOutputStream os = new FileOutputStream(file)) {
os.write(bytes);
} catch (Exception e) {
System.err.print("imagen Error wri " + imagen.getImageData() + "\n");
}
This line does not fill the raw file:
(If I change raw to png then it does fill the file.)
ImageIO.write(imagenBuffered, "raw", baos);
This line of code with png is created correctly:
ImageIO.write(imagenBuffered, "png", baos);
You cannot use ImageIO to write raw. You could get the "raw bytes" of your image and write them to a file though.
If you already have your buffered image, you could try the inverse of this answer. https://stackoverflow.com/a/54578326/2067492
int[] rgb = imagenBuffered.getRGB(0, 0, width, height, null, width);
ByteBuffer bb = ByteBuffer.allocate( rgb.length*4 );
bb.asIntBuffer().put(rgb);
bytes = bb.array();
This would write all of the pixels to a byte[], no headers or information about the data, just 4 byte rgba as returned by getRGB.
I want to use Gravatar but I don't want to publish users MD5 hashes of their e-mail addresses. And there is more potential problems. So I decided to download them and store them in my database.
But I have a problem with such a simple task as my profile picture (Earlybird) looks bad after downloading:
This is the code I used.
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
final URL url = new URL("http://www.gravatar.com/avatar/" + account.getGravatarHash() + "?d=identicon");
final BufferedImage image = ImageIO.read(url);
ImageIO.write(image, "jpg", baos);
pic = baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
Value in pic is then directly stored to the database. Other pictures in my database are stored fine so problem must be in these lines.
EDIT:
I just partially fix the problem by changing "jpg" for a "png" even thought Gravatar tutorial is mentioning "jpg". Also I don't want to specify image format (unless all Gravatars are png). Can I avoid that? I want just save the bytes I get.
Browsers in most cases work with raw bytes. However it is highly appreciated to send "Content-Type: image/..." header for each image.
When you save bytes in DB you also have to
either save image content type, provided by Gravatar for this image or
convert image into your default format, so you can to hardcode content type for all images from your DB
To get headers, provided by Gravatar, you can use Apache HTTP Client.
To convert image into your preferred format, you can use ImageIO.
I found one similar problem with working solution:
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()){
final URL url = new URL("http://www.gravatar.com/avatar/" + account.getGravatarHash() + "?d=identicon");
InputStream inputStream = url.openStream();
byte[] buffer = new byte[1024];
int n;
while (-1 != (n = inputStream.read(buffer))) {
baos.write(buffer, 0, n);
}
inputStream.close();
pic = baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
Looks like this works with png and jpg Gravatars.
I have this following code in my servlet
response.setContentType("image/gif");
String filepath = "PATH//TO//GIF.gif";
OutputStream out = response.getOutputStream();
File f = new File(filepath);
BufferedImage bi = ImageIO.read(f);
ImageIO.write(bi, "gif", out);
out.close();
This code is just returning first frame of the image.
How to achieve returning full GIF image ?
Your GIF does not animate, because you are sending only the first frame to the client. :-)
Actually, you are, because ImageIO.read reads only the first frame (and a BufferedImage can only contain a single frame/image). You are then writing that single frame to the servlet output stream, and the result will not animate (it should be possible to create animating GIFs using ImageIO, but the code to do so will be quite verbose, see How to encode an animated GIF in Java, using ImageWriter and ImageIO? and Creating animated GIF with ImageIO?).
The good news is, the solution is both simple, and will save you CPU cycles. There's no need to involve ImageIO here, if you just want to send an animated GIF that you have stored on disk. The same technique can be used to send any binary content, really.
Instead, simply do:
response.setContentType("image/gif");
String filepath = "PATH//TO//GIF.gif";
OutputStream out = response.getOutputStream();
InputStream in = new FileInputStream(new File(filepath));
try {
FileUtils.copy(in, out);
finally {
in.close();
}
out.close();
FileUtils.copy can be implemented as:
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();
}
I trying to build RDP application for android mobile.so in server side i am sending the png images with the robot class, but in client side i am not able to read that messages and print them on my android device.
i am using following code to read the JPEG file body data and i am able to show those images
InputStream in = sock.getInputStream();
while(true)
{
byte[] bytes = new byte[1024*1024];
int count = 0;
do
{
count+= in.read(bytes,count,bytes.length-count);
}
while(!(count>4&&bytes[count-2]==(byte)-1 && bytes[count-1]==(byte)-39));
}
can any one help me how to read the png file out of the inputstream.
Try this
BufferedInputStream in = new BufferedInputStream(sock.getInputStream());
BufferedImage image = ImageIO.read(in);
I want to show an image as it is downloading, I have the URL, and I am trying to get the image parts like this:
InputStream openStream = url.openStream();
DataInputStream dis = new DataInputStream(new BufferedInputStream(openStream));
ByteArrayOutputStream os = new ByteArrayOutputStream();
while ((s = dis.read(b)) != -1) {
os.write(b , 0, s);
support.firePropertyChange("stream", null, os);
}
This way, any listener get the stream and creates an image, this way:
if("stream".equals(evt.getPropertyName())){
try {
ByteArrayOutputStream stream = (ByteArrayOutputStream) evt.getNewValue();
byte[] byteArray = stream.toByteArray();
stream.flush();
Image createImage = Toolkit.getDefaultToolkit().createImage(byteArray);
this.getContentPane().add(new JLabel(new ImageIcon(createImage)));
} catch (IOException ex) {
Logger.getLogger(ImageTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
However, I am getting a "Premature end of JPEG file sun.awt.image.ImageFormatException: JPEG datastream contains no image" error, the image is a JPG image format, is there any library or method known to make something similar?
It would depend on the image decoder, but you could try ImageObserver. There's an example in Tracking Image Loading: MediaTracker and ImageObserver.