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.
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've the following code:
File file = new File(filepath);
byte[] fileData = new byte[(int) file.length()];
DataInputStream dis = null;
try {
dis = new DataInputStream(new FileInputStream(file));
dis.readFully(fileData);
dis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Bitmap bm = BitmapFactory.decodeByteArray(fileData,0, fileData.length);
I succesfully manage to fill fileData with bytes, although to be honest I think there are too few bytes to represent the content of the jpg file referenced by filepath. But as even if I set it to have more bytes they are left as 0, I guess it contains the proper bytes.
But once the last instruction is executed bm is left as null.
What could I do so I can properly get the bitmap from that data?
PD: I'm aware it would be more logical to do:
Bitmap bm = BitmapFactory.decodeFile(filePath);
But, for some reason, that also returns null, so I'm taking this less direct approach to try to solve the issue.
After some investigation, I've checked that problem is that just a few bytes are the one being retrieved, with that, it's no brainer bitmpa ends up being null, what could I do so I get all bytes?
I have following method for coping jpg photos from one folder to another:
public static void copyImage(String from, String to) {
try {
File sourceimage = new File(from);
BufferedImage image = ImageIO.read(sourceimage);
ImageIO.write(image, "jpg", new File(to));
} catch (IOException ex) {
Logger.getLogger(ImgLib.class.getName()).log(Level.SEVERE, null, ex);
} catch (NullPointerException ex){
Logger.getLogger(ImgLib.class.getName()).log(Level.SEVERE, null, ex);
}
}
It works, but little bit loosing quality of photo.
How I can achieve "perfect" cloning without loosing quality?
Yes, you are right. In this line:
ImageIO.write(image, "jpg", new File(to));
Your method is still re-encoding the image data which, with a lossy format like JPEG, will inevitably cause a loss of fidelity in the image.
I think, you may try to copy the image file using this code:
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(new File("path/to/img/src"));
os = new FileOutputStream(new File("path/to/img/dest"));
byte[] buffer = new byte[8192];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
} finally {
is.close();
os.close();
}
Also, you may Apache Commons IOUtils to simplify copying from one stream to the other or if you are using Java 8 then you can just call Files.copy method.
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(new File("path/to/img/src"));
os = new FileOutputStream(new File("path/to/img/dest"));
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
} finally {
is.close();
os.close();
}
You have used BufferedImage which read the file into a image object.
instead you should read and write image file in the same way as you do with binary files (use InputStraem and OutputStream).
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());
public void actionPerformed(java.awt.event.ActionEvent evt) {
Connection cn = null;
Object source = evt.getSource();
JFileChooser filechooser= new JFileChooser();
filechooser.setDialogTitle("Choose Your File");
filechooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int returnval=filechooser.showOpenDialog(this);
if(returnval==JFileChooser.APPROVE_OPTION)
{
File file = filechooser.getSelectedFile();
BufferedImage bi;
try
{
bi=ImageIO.read(file);
lbl_movieCover.setIcon(new ImageIcon(bi));
}
catch(IOException e)
{
}
//this.pack();
}
Above is my code for choosing the image and displaying the image to JLabel. My problem is that, I don't know how to convert it to byte[] so I could save it to my database. By the way, I'm using MySQL for my database. If you guys know how to do it, please let me know.
Use ImageIO.write to write the image through a ByteArrayOutputStream, for example
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
ImageIO.write(bi, "png", baos);
} finally {
try {
baos.close();
} catch (Exception e) {
}
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
You can then use the resulting byte[] array or ByteArrayInputStream and pass this to the setBlob method of a PreparedStatement
You could use a ByteArrayOutputStream and ImageIO to write an image to a byte array, like this:
static byte[] imageToByteArray(BufferedImage image) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
ImageIO.write(image, "png", stream);
} catch(IOException e) {
// This *shouldn't* happen with a ByteArrayOutputStream, but if it
// somehow does happen, then we don't want to just ignore it
throw new RuntimeException(e);
}
return stream.toByteArray();
// ByteArrayOutputStreams don't need to be closed (the documentation says so)
}
You can use this method-
/**
* #param userSpaceImage
* #return byte array of supplied image
*/
public byte[] getByteData(BufferedImage userSpaceImage) {
WritableRaster raster = userSpaceImage.getRaster();
DataBufferByte buffer = (DataBufferByte) raster.getDataBuffer();
return buffer.getData();
}
Use it like-
//file from filechooser
BufferedImage originalImage = ImageIO.read(file);
byte image[] = getByteData(originalImage);
Note that if image type is that of int e.g. BufferedImage.TYPE_INT_RGB then
you will get cast exception. Following method can be used to convert to suitable type-
/**
* this method convert supplied image to suitable type
* it is needed because we need bytes of array so TYPE_INT images must be
* converted to BYTE_BGR or so
* #param originalImage loaded from file-chooser
* #return
*/
public BufferedImage convertImage(BufferedImage originalImage) {
int newImageType = originalImage.getType();
/**
* Converting int to byte since byte array is needed later to modify
* the image
*/
if (newImageType == BufferedImage.TYPE_INT_RGB
|| newImageType == BufferedImage.TYPE_INT_BGR) {
newImageType = BufferedImage.TYPE_3BYTE_BGR;
} else if (newImageType == BufferedImage.TYPE_INT_ARGB) {
newImageType = BufferedImage.TYPE_4BYTE_ABGR;
} else if (newImageType == BufferedImage.TYPE_INT_ARGB_PRE) {
newImageType = BufferedImage.TYPE_4BYTE_ABGR_PRE;
}
BufferedImage newImage = new BufferedImage(originalImage.getWidth(),
originalImage.getHeight(), newImageType);
Graphics g = newImage.getGraphics();
g.drawImage(originalImage, 0, 0, null);
g.dispose();
return newImage;
}
While both #MadProgrammer's and #immibis' answers are technically correct and answers your question, you don't really want to copy an image file by decoding it, and re-encoding it. This is because it's slower, but more importantly, you will lose quality for certain image formats (most notably JPEG) and any metadata associated with the image will be lost (this last part could of course be intentional, but there are better ways to do this without ruining the image quality).
So, instead, do as #immibis seems to hint at in his comment, just open a FileInputStream and read the bytes directly from the file, and into the database. You should be able to open an OutputStream to the blob in your database as well, so you can save some memory (a good thing, if your files are large) by not reading the entire file contents into a byte array, before writing.
Something like:
File file = filechooser.getSelectedFile();
// ... show image in label as before (but please, handle the IOException)
InputStream input = new FileInputStream(file);
try {
Blob blob = ...; // Get from JDBC connection
OutputStream output = blob.setBinaryStream(0);
try {
FileUtils.copy(input, output);
}
finally {
output.close();
}
}
finally {
input.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();
}