Issues reading/writing images - java

I have been working on code to encrypt and decrypt images via a Spring webapp in which i use Thymeleaf. I have tested each method involved in the process and each one is sound. The way the process flows is supposed to be:
User1 uploads image and key, app breaks down image into pixels and then into 128-bit stateHexes, stateHexes are encrypted using AES, and rebuilt into encrypted image to be displayed to User1 for download. User1 then sends image to User2 who then downloads image and decrypts it using the same process.
When I treat it like the above scenario the image somehow changes after storing it. However, if i treat it as follows the file encrypts and decrypts perfectly.
So I assume the issue must lie in either saving the file or retrieving the file, or some other issue pertaining to file handling.
Below I will show code snippets of how i load and save the images.
This is how I get the image
// Get the filename and path for the image passed in from user
Path fileNameandPath = Paths.get(uploadDirectory, file.getOriginalFilename());
// Generate the file and write the image onto it
File imageFile = fileNameandPath.toFile();
BufferedImage image = null;
try {
Files.write(fileNameandPath, file.getBytes());
image = ImageIO.read(imageFile);
Files.delete(fileNameandPath);
} catch (IOException e) {
e.printStackTrace();
System.out.println("COULDNT READ IMAGE AT = " + fileNameandPath);
}
And this is how I create the outputImage
String outputFilePath = new File("src/main/resources/static").getAbsolutePath() + "\\output.jpg";
File outputFile = new File(outputFilePath);
try {
outputFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
System.out.println("FILE ALREADY EXISTS");
}
// Write the image to the outputfile
try {
ImageIO.write(outputImage, "jpg", outputFile);
} catch (IOException e) {
e.printStackTrace();
}
I pass in an all black image (each pixel's hex code is 000000) and it reads the image and encrypts as expected, but when decrypting it reads in the previous image wrong, leading me to believe that it's not the code but most likely how the file is stored/retrieved? I only have one guess: that somehow the file is getting mixed up. If anyone has any clues as to why this happening, any help or leads would be appreciated.
I think it may have to do with how I write to the image. Reading the image is no problem, but how I write to the image seems to alter it in a way.

After getting some sleep, I realized that because I need the image to remain the same when reading and writing, I was losing bits of the image due to the lossy nature of .jpg files. Now that I save my file as a .png I get no errors. Hope this helps someone down the road!

Related

Servlet interaction with filesystem: storing files and generating URLs for clientside access

SUMMARY
I need to store both uploaded and server-generated images, with portable and
predictable paths so my server code is aware of where these images exist.
I need to generate URLs to these images that can be sent to the client. These URLs will be used in HTML image elements.
PROBLEM
My web application allows the user to upload an image, using gwtupload(Apache Commons). This image is stored on the server and a URL returned to the client so the image is shown. gwtupload provides a clientside method to get this URL for the uploaded image. This works in deployment; the following aspects do not:
In certain cases, the uploaded image must be cropped. This results in
a new image being generated by a servlet method. I want to store this
cropped image and return(to the client) an access URL.
Then, this image is used by another method to generate another
image. This method must know the location on the file system of
the previously uploaded(and/or cropped) image. A URL for the new
image must then be returned to client.
I have implementation working perfectly in GWT development mode. However, as I expected, after deployment to my own Tomcat server, the remote services fail due to my confusion regarding the file system. I do not know the correct way of storing these images in a predictable place on the server filesystem, nor do I know how to generate access URLs(for files residing outwith the WAR, as these images will.)
All these images are only needed for the current session, so the locations can be temporary directories. I have spent two days experimenting and trawling the web for a solution to no avail.
I will post abridged code below. This is my attempt to simply use the working directory and relative pathnames. Using the Eclipse debugger attached to my servlet container, I could see the results of String dataDir = context.getRealPath("foo") indicating a temp folder within the servlet: but when I navigated there using explorer, NONE of the files had been written to the disk. I am very confused.
public String[] generatePreview(String xml) {
PreviewManager manager = new PreviewManager();
String url;
try{
preview = manager.generatePreview(xml);
}
catch (Exception e){e.printStackTrace();}
//Create the preview directory
File folder = new File("previews");
if (!folder.exists()) folder.mkdir();
//The file to be written to
File output = new File(folder, "front.jpg");
ServletContext context = getServletContext();
String dataDir = context.getRealPath("previews");
try {
ImageIO.write(image, "jpg", output);
} catch (IOException e) {
e.printStackTrace();
}
url = "previews/" + output.getName();
return url;
}
#Override
public String cropBackground(int[] coord_pair, String relativePath) {
File backgroundsFolder = new File("backgrounds");
if (!backgroundsFolder.exists()) backgroundsFolder.mkdir();
ServletContext context = getServletContext();
String dataDir = context.getRealPath("backgrounds");
File current = new File(relativePath);
String croppedName = "cropped_" + relativePath.replace("./backgrounds/", "");
int x = coord_pair[0];
int y = coord_pair[1];
int width = coord_pair[2];
int height = coord_pair[3];
String croppedPath = null;
try {
croppedPath = imageCropper.createCroppedImage(current, "backgrounds", croppedName, x, y, width, height);
}
catch (IOException e){
e.printStackTrace();
}
current.delete();
return "backgrounds/" + croppedPath;
I am aware that my current 'return' statements would never work in deployment: I need to generate the URLs properly and return as strings. I'm sorry about the question length but I wanted to make my problem clear.
Choose a directory where your images will be stored, outside of Tomcat. Assign some unique ID to each uploaded or generated image, and store the images in this directory (with the ID as file name, for example).
Generate URLs to an image servlet that will read the image by ID in this directory, and send the bytes of the image to the output stream of the servlet response : image.action?id=theImageId.

How to store an image as BLOB and then display in Play!-powered website?

I am trying to create an initial-data.yml file for a Play! Framework application. Part of the web application involves images (for profile picture and such) and I want to store them as BLOBs in my MySQL database (I know this isn't best practice, use of a file system will come later). I am wondering how I can put a "test" image in my YML file and how I can access it in the web app and display it. Any help would be appreciated. Below is what I have tried so far:
Part of YML:
Picture(Picture1):
picture: 010001010100010101000101010001010100010101000101010001010100010101000101010001010100010101000101010001010100010101000101|image/png
Our Hibernate model has a picture as a byte[].
Here is how I am trying to access the image in the HTML:
#{if _post.picture}
<!-- display the picture -->
<p> Hey, a picture should go here.</p>
<img src="#{Application.showImage(_post.getPicture().getBinaryImage())}" alt="long islands for life"/>
#{/if}
Here is getBinaryImage()
private ByteArrayInputStream getBinaryImage() {
try {
BufferedImage image = ImageIO.read(new ByteArrayInputStream(byteImage));
ImageInputStream is = ImageIO.createImageInputStream(image);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
return bais;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Right now I am getting a NullPointerException on the first line of this method because it seems that the image/byte[] is not being stored in the database. Any ideas how to get this appropriately stored in the database and then displaying on the webpage?
You should add your whole binary data in Base64 encoded form prepended by !!binary
binaryData: !!binary VGhpcyBTdHJpbmcgaXMgc3RvcmVkIGluIHlhbWwgZmlsZSB1c2luZyBiYXNlNjQ=
This example is from Play Framework samples
samples-and-tests/just-test-cases/test/yamlTestData.yml

How to check a uploaded file whether it is an image or other file?

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.
} else {
// It's not 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, JPEG, PNG, TIFF or WBMP types (but not 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, JPEG, PNG, TIFF and WBMP 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 signatures. For example Apache Tika which recognizes on top of ImageIO formats also PSD, BPG, WEBP, ICNS and SVG as well:
Tika tika = new Tika();
try (InputStream input = uploadedFile.getInputStream()) {
String mimeType = tika.detect(input);
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");
}
}

In Java 1.6 how to serve a JPEG in memory through an HTTPHandler?

I am working on creating a simple HTTP server as part of a Java server. One component of this Java server is to capture images live from a webcam. Currently I am writing the images out to disk, and serving them through Apache.
What I want to do in the end though is write the JPEG to memory in a List of JPEG objects and then have a HTTPHandler that will serve the appropriate image when requested.
I don't see any clear way to do this. Anyone have any ideas?
Here is how I am getting the images, using LTI CIVIL as the capture library - This is saving them to disk - I want to store them in memory:
try
{
String fileName = "image" + System.currentTimeMillis() + ".jpg";
FileOutputStream os = new FileOutputStream(FILE_PATH + fileName);
final JPEGImageEncoder jpeg = JPEGCodec.createJPEGEncoder(os);
jpeg.encode(AWTImageConverter.toBufferedImage(image));
os.close();
log.info("Got image as filename: " + fileName);
}
catch (Exception e)
{
log.error("An error occured", e);
}
If you use a ByteArrayOutputStream instead of a FileOutputStream you can capture the output and then call toByteArray to get the data once it's finished writing.
As for serving it, when you get a request for the image, set the content type to "image/jpeg", set the content length to the length of the byte array, then write the bytes to the response's output stream.

How to use ImageIO to save multiple BufferedImages to a file

I tried both of the following options:
1.
BufferedImage Buffered_Image;
MemoryCacheImageOutputStream MemoryCache_OutputStream =
new MemoryCacheImageOutputStream(new FileOutputStream("C:/Test.mov",false));
while (notFinished) // Main recording loop.
{
Buffered_Image=robot.createScreenCapture(); // Capture Screen image.
try { ImageIO.write(Buffered_Image,"png",MemoryCache_OutputStream); }
catch (Exception e) { e.printStackTrace(); }
}
2.
BufferedImage Buffered_Image;
ImageWriter writer;
try
{
ImageOutputStream ios=ImageIO.createImageOutputStream(new File("C:/Test.mov"));
Iterator writers=ImageIO.getImageWritersByFormatName("png");
while (writers.hasNext())
{
writer=(ImageWriter)writers.next();
writer.setOutput(ios);
Out(writer.toString()+" canInsertImage : "+writer.canInsertImage(0));
// Got this: com.sun.imageio.plugins.png.PNGImageWriter#19fcc69
// canInsertImage : false
}
}
catch (Exception e) { }
cntPics=0;
while (notFinished) // Main recording loop.
{
Buffered_Image=robot.createScreenCapture(); // Capture Screen image.
writer.write(null,new IIOImage(Buffered_Image,null,null),null);
if (writer.canInsertImage(-1)) {
// Append image at highest index
writer.writeInsert(-1,new IIOImage(Buffered_Image,null,null),null);
} else Out("Writer can’t append image Id : "+cntPics);
cntPics++;
}
Neither of them worked, what's the correct way to save multiple PNG images to a file?
Edit:
You are right, I found a java program called Krut that can record screen sessions, but it uses JPEGImageEncoder, the image quality isn't as good as I want, so I wonder if I can use ImageIO to encode the sequence.
If ImageIO can't do it, my next question would be is there a stand alone open source PNGImageEncoder that I can use to encode it? I know there are open source PNGImageEncoders, but they tend to be tangled in projects and hard to get all the supporting files out of it, any ideas? Thanks!
It looks like you're trying to create a video (MOV) file by writing multiple PNG files in a row. This isn't going to work. You'll probably have to find a third-party library for encoding your images into a video file (which is itself may be a good SO question).
EDIT: I should also note that you may actually be able to get video by writing multiple JPG images in a row to get a form of MJPEG (Motion JPEG) but for other formats such as MOV you're going to need an actual encoder.
What are you trying to do? Re-inventing MNG? Even if you can write multiple PNG images in the same file, it makes a compound file understood by no program (except those you might write).
If, as suggested by Marc, you want to make a movie, you might want to look at QuickTime for Java (QTJava). It is the solution used by Processing to make movies out of animations/frames. It has several quality/formats, from the worst (but small files) to the highest quality (high file sizes as result).

Categories

Resources