I need to crop an image from the web (via its url) and return an InputStream (which can be uploaded to AWS S3). I am using org.imgscalr as the library and have the following method:
public InputStream cropFile(String url) throws Exception, IOException {
BufferedImage original = ImageIO.read(new URL(url));
BufferedImage target = null;
// resize based on http://www.htmlgoodies.com/beyond/java/create-high-quality-thumbnails-using-the-imgscalr-library.html
target = Scalr.crop(original, 410, 60, 200, 300, Scalr.OP_ANTIALIAS);
InputStream is = (InputStream) ImageIO.createImageInputStream(target);
Assert.assertNotNull(is);// it always returns null!!!
return is;
}
I call the method with something like:
InputStream is = cropFile("http://fengyuanchen.github.io/cropperjs/img/picture.jpg");
and then try to upload it to AWS S3:
PutObjectRequest request = new PutObjectRequest(AWSConfig.getBucket(), key, is, meta);
s3.putObject(request);
Unfortunately, I keep getting a null input stream (at the assert point above). If I change the createImage to:
ImageIO.write(target, "jpg", new File("c:\\dest.jpg"));
Then a proper image is written (so it works).
Related
I am uploading a jpg to a spring controller endpoint. The image is uploaded as Base64 image/jpg which comes in as a MultipartFile. I am decoding the inputstream using Base64Decoder which seems to decode it ok but when I turn it into an InputStream to write it out to disk I can see it's been modified (according to what I can see in the debugger). When I save the file and open it it says it's an unsupported file type.
I took the multipart inputstream and wrote it directly to disk and I see the base64 encoding in notepad.
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4QBgRXhpZgAASUkqAAgAAAACADEBAgAHAAAAJgAAAGmHBAABAAAALgAAAAAAAABHb29nbGUAAAMAAJAHAAQAAAAwMjIwAqAEAAEAAAAACAAAA6AEAAEAAAAABgAAAAAAAP/bAIQAAwICCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCggKCgoKCgoICAgKCgoICAgICgoICAgKCgoICA0NCggNCAgKCAEDBAQGBQYIBgYICA0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI/8AAEQgGAAgAAwEiAAIRAQMRAf/EAB0AAAIDAQEBAQEAAAAAAAAAAAMEAgUGAQAHCAn/xABJEAABAwIDBgQFBAIBAwMCAA8BAAIRAyEEMUEFElFhcfAGgZGhEyKxwdEHMuHxFEJSFSNiCDNyFoKSFyRDU6LCCTRjRHOy0uL/xAAbAQEBAQEBAQEBAAAAAAAAAAAAAQIDBAUGB//EACoRAQEBAQACAwADAAEEAwEBAQABEQIDcRIhMQQTsVEUIjJBBWGBwUIj/9oADAMBAAIRAxEAPwCgrFsRw4ZfWEs2FXUN4C7p4c10702ML4/M+p6jhzfqep/i4p0uS9Vtw8vddwRkX7t+ck1TdElWusVNVsRY3K1ngx2YFsz5rMYytJHX+7rSeDWGf6XHqf8A0938eZ02zK8LlWoMzwP9LwCV2jxC81j7kswTAYsE2Xto1OAzVPslvzHT8K8LV
Here's my controller and my code:
#PostMapping(value = "/saveBlueprintOrder")
public ResponseEntity<?> saveBlueprintOrder(#RequestParam MultipartFile blueprint,
#RequestParam(required = false) MultipartFile coversheet,
#RequestParam(required = false) MultipartFile logo,
#ModelAttribute BlueprintOrder blueprintOrder) {
if(coversheet != null) {
BASE64Decoder decoder1 = new BASE64Decoder();
byte[] imageBytes = decoder1.decodeBuffer(coversheet.getInputStream());
InputStream bis = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(bis);
ImageIO.write(image, "jpg", new File("C:\\Users\\i58287\\Downloads\\coversheet.jpg"));
OutputStream stream = new FileOutputStream("C:\\Users\\i58287\\Downloads\\coversheet-test.jpg");
stream.write(imageBytes);
stream.close();
I just need to be able to translate this image to an inputstream so I can check the image locally in addition I need to send it to another api as such. What am I missing that's causing this image to be un-openable? Thanks for any help!
PS: I've done a lot of combinations so this is showing a couple options I have tried, BufferedImage image = ImageIO.read(bis) keeps returning a null image.
Ok so I don't know WHY this is what I had to do but I ended up saving my byte[] as a String and cut off the pre-pended
data:image/jpeg;base64
Then I decoded it into an InputStream. Anyone know why I had to do this?
Here's the code:
String imageBytes = new String(coversheet.getBytes(), StandardCharsets.UTF_8);
String imageDataBytes = imageBytes.substring(imageBytes.indexOf(",") + 1);
InputStream stream = new ByteArrayInputStream(Base64.getDecoder().decode(imageDataBytes.getBytes()));
BufferedImage image = ImageIO.read(stream);
ImageIO.write(image, "jpg", new File("C:\\Users\\i58287\\Downloads\\coversheet-test.jpg"));
I have Java Spring MVC application in which there is an option to upload an image and save to the server. i have the following method:
#RequestMapping(value = "/uploaddocimagecontentsubmit", method = RequestMethod.POST)
public String createUpdateFileImageContentSubmit(#RequestParam("file") MultipartFile file, ModelMap model)
{
//methods to handle file upload
}
I am now trying to reduce the size of the image refering the following:
increasing-resolution-and-reducing-size-of-an-image-in-java and decrease-image-resolution-in-java
The problem I am facing is that in the above examples, we are dealing with java.io.File Objects which are saved to a specified location. I dont want to save the image. Is there any way that I can use something similar to compress my Multipart Image file and continue with the upload.
Why don't you resize it on the client before upload? That will save some bandwidth
BlueImp JQuery Upload can do this
It was my first time taking a deep dive into the ImageIO package. I came across the MemoryCacheImageOutputStream, which allows you to write an image output stream to an output stream, i.e. ByteArrayOutputStream. From there, The data can be retrieved using toByteArray() and toString(), after compression. I used toByteArray, as I am storing images to postgresql and it stores the images as a byte array. I know this is late, but I hope it helps someone.
private byte[] compressImage(MultipartFile mpFile) {
float quality = 0.3f;
String imageName = mpFile.getOriginalFilename();
String imageExtension = imageName.substring(imageName.lastIndexOf(".") + 1);
// Returns an Iterator containing all currently registered ImageWriters that claim to be able to encode the named format.
// You don't have to register one yourself; some are provided.
ImageWriter imageWriter = ImageIO.getImageWritersByFormatName(imageExtension).next();
ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // Check the api value that suites your needs.
// A compression quality setting of 0.0 is most generically interpreted as "high compression is important,"
// while a setting of 1.0 is most generically interpreted as "high image quality is important."
imageWriteParam.setCompressionQuality(quality);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// MemoryCacheImageOutputStream: An implementation of ImageOutputStream that writes its output to a regular
// OutputStream, i.e. the ByteArrayOutputStream.
ImageOutputStream imageOutputStream = new MemoryCacheImageOutputStream(baos);
// Sets the destination to the given ImageOutputStream or other Object.
imageWriter.setOutput(imageOutputStream);
BufferedImage originalImage = null;
try (InputStream inputStream = mpFile.getInputStream()) {
originalImage = ImageIO.read(inputStream);
} catch (IOException e) {
String info = String.format("compressImage - bufferedImage (file %s)- IOException - message: %s ", imageName, e.getMessage());
logger.error(info);
return baos.toByteArray();
}
IIOImage image = new IIOImage(originalImage, null, null);
try {
imageWriter.write(null, image, imageWriteParam);
} catch (IOException e) {
String info = String.format("compressImage - imageWriter (file %s)- IOException - message: %s ", imageName, e.getMessage());
logger.error(info);
} finally {
imageWriter.dispose();
}
return baos.toByteArray();
}
I'm trying to read parts from a big image in java. My image size is more than 700 MB. I have used this code which normally reads pixels without loading the whole image into memory:
Rectangle sourceRegion = new Rectangle(0, 0, 512, 512); // The region you want to extract
ImageInputStream stream = ImageIO.createImageInputStream( new File("/home/dhoha/Downloads/BreastCancer.jp2")); // File or input stream
final Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
if (readers.hasNext()) {
ImageReader reader = (ImageReader)readers.next();
reader.setInput(stream, true);
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(sourceRegion); // Set region
BufferedImage image = reader.read(0, param); // Will read only the region specified
However, I got the error:
Exception in thread "main" java.lang.IllegalArgumentException: Dimensions (width=95168 height=154832) are too large
at java.awt.image.SampleModel.<init>(SampleModel.java:130)
at java.awt.image.ComponentSampleModel.<init>(ComponentSampleModel.java:146)
at java.awt.image.PixelInterleavedSampleModel.<init>(PixelInterleavedSampleModel.java:87)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.createSampleModel(J2KRenderedImageCodecLib.java:741)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.createOriginalSampleModel(J2KRenderedImageCodecLib.java:729)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.<init>(J2KRenderedImageCodecLib.java:261)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderCodecLib.read(J2KImageReaderCodecLib.java:364)
at testJai2.test3.main(test3.java:21)
Any help please to read parts from this big image?
There are different ways to load parts of image to memory and then process it afterwards. You can try out the following method to read fragments:
public static BufferedImage readFragment(InputStream stream, Rectangle rect)
throws IOException {
ImageInputStream imageStream = ImageIO.createImageInputStream(stream);
ImageReader reader = ImageIO.getImageReaders(imageStream).next();
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(rect);
reader.setInput(imageStream, true, true);
BufferedImage image = reader.read(0, param);
reader.dispose();
imageStream.close();
return image;
}
And calling it like this:
URL url = new URL("..."); // You can use your own stream instead of URL
Image chunk = readFragment(url.openStream(), new Rectangle(150, 150, 300, 250));
This is marked as a correct answer in this thread.
You can use this technique to finally read the whole image into the memory if you need by doing some simple calculations.
EDIT:
The resolution of the image you are trying to process is larger than an array can have (95168x154832). So basically you will not be able to read the image, since ImageIO.createImageInputStream() tries to load the whole image into an array AFAIK.
What you can do is use a library called ImgLib2. Here you can find some examples. ImgLib2 uses multidimensional arrays to read the (big) image data and so it's larger than ImageIO can handle.
It seems to me there are two ways to store an attachment in a NotesDocument.
Either as a RichTextField or as a "MIME Part".
If they are stored as RichText you can do stuff like:
document.getAttachment(fileName)
That does not seem to work for an attachment stored as a MIME Part. See screenshot
I have thousands of documents like this in the backend. This is NOT a UI issue where I need to use the file Download control of XPages.
Each document as only 1 attachment. An Image. A JPG file. I have 3 databases for different sizes. Original, Large, and Small. Originally I created everything from documents that had the attachment stored as RichText. But my code saved them as MIME Part. that's just what it did. Not really my intent.
What happened is I lost some of my "Small" pictures so I need to rebuild them from the Original pictures that are now stored as MIME Part. So my ultimate goal is to get it from the NotesDocument into a Java Buffered Image.
I think I have the code to do what I want but I just "simply" can't figure out how to get the attachment off the document and then into a Java Buffered Image.
Below is some rough code I'm working with. My goal is to pass in the document with the original picture. I already have the fileName because I stored that out in metaData. But I don't know how to get that from the document itself. And I'm passing in "Small" to create the Small image.
I think I just don't know how to work with attachments stored in this manner.
Any ideas/advice would be appreciated! Thanks!!!
public Document processImage(Document inputDoc, String fileName, String size) throws IOException {
// fileName is the name of the attachment on the document
// The goal is to return a NEW BLANK document with the image on it
// The Calling code can then deal with keys and meta data.
// size is "Original", "Large" or "Small"
System.out.println("Processing Image, Size = " + size);
//System.out.println("Filename = " + fileName);
boolean result = false;
Session session = Factory.getSession();
Database db = session.getCurrentDatabase();
session.setConvertMime(true);
BufferedImage img;
BufferedImage convertedImage = null; // the output image
EmbeddedObject image = null;
InputStream imageStream = null;
int currentSize = 0;
int newWidth = 0;
String currentName = "";
try {
// Get the Embedded Object
image = inputDoc.getAttachment(fileName);
System.out.println("Input Form : " + inputDoc.getItemValueString("form"));
if (null == image) {
System.out.println("ALERT - IMAGE IS NULL");
}
currentSize = image.getFileSize();
currentName = image.getName();
// Get a Stream of the Imahe
imageStream = image.getInputStream();
img = ImageIO.read(imageStream); // this is the buffered image we'll work with
imageStream.close();
Document newDoc = db.createDocument();
// Remember this is a BLANK document. The calling code needs to set the form
if ("original".equalsIgnoreCase(size)) {
this.attachImage(newDoc, img, fileName, "JPG");
return newDoc;
}
if ("Large".equalsIgnoreCase(size)) {
// Now we need to convert the LARGE image
// We're assuming FIXED HEIGHT of 600px
newWidth = this.getNewWidth(img.getHeight(), img.getWidth(), 600);
convertedImage = this.getScaledInstance(img, newWidth, 600, false);
this.attachImage(newDoc, img, fileName, "JPG");
return newDoc;
}
if ("Small".equalsIgnoreCase(size)) {
System.out.println("converting Small");
newWidth = this.getNewWidth(img.getHeight(), img.getWidth(), 240);
convertedImage = this.getScaledInstance(img, newWidth, 240, false);
this.attachImage(newDoc, img, fileName, "JPG");
System.out.println("End Converting Small");
return newDoc;
}
return newDoc;
} catch (Exception e) {
// HANDLE EXCEPTION HERE
// SAMLPLE WRITE TO LOG.NSF
System.out.println("****************");
System.out.println("EXCEPTION IN processImage()");
System.out.println("****************");
System.out.println("picName: " + fileName);
e.printStackTrace();
return null;
} finally {
if (null != imageStream) {
imageStream.close();
}
if (null != image) {
LibraryUtils.incinerate(image);
}
}
}
I believe it will be some variation of the following code snippet. You might have to change which mimeentity has the content so it might be in the parent or another child depending.
Stream stream = session.createStream();
doc.getMIMEEntity().getFirstChildEntity().getContentAsBytes(stream);
ByteArrayInputStream bais = new ByteArrayInputStream(stream.read());
return ImageIO.read(bais);
EDIT:
session.setConvertMime(false);
Stream stream = session.createStream();
Item itm = doc.getFirstItem("ParentEntity");
MIMEEntity me = itm.getMIMEEntity();
MIMEEntity childEntity = me.getFirstChildEntity();
childEntity.getContentAsBytes(stream);
ByteArrayOutputStream bo = new ByteArrayOutputStream();
stream.getContents(bo);
byte[] mybytearray = bo.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(mybytearray);
return ImageIO.read(bais);
David have a look at DominoDocument,http://public.dhe.ibm.com/software/dw/lotus/Domino-Designer/JavaDocs/XPagesExtAPI/8.5.2/com/ibm/xsp/model/domino/wrapped/DominoDocument.html
There you can wrap every Notes document
In the DominoDocument, there such as DominoDocument.AttachmentValueHolder where you can access the attachments.
I have explained it at Engage. It very powerful
http://www.slideshare.net/flinden68/engage-use-notes-objects-in-memory-and-other-useful-java-tips-for-x-pages-development
I'm trying to create a BufferedImage from a ByteArrayInputStream with:
byte[] imageData = getData(imageFile); // returns file as byte[]
InputStream inputStream = new ByteArrayInputStream(imageData);
String format = getFormatName(inputStream);
BufferedImage img = ImageIO.read(inputStream);
But img is always null. The input stream is valid (since I use it before to get the image format).
What could be making ImageIO return null? Do I need to use flush or close in any place?
Your call to getFormatName consumes the inputStream, so the stream pointer is at the end of the byte array. Any try to read from that stream will tell that it's at the end of the 'file'. You need to reset the stream (or create a new one) before you hand it over to the ImageIO.read() method:
String format = getFormatName(new ByteArrayInputStream(imageData));
BufferedImage img = ImageIO.read(new ByteArrayInputStream(imageData));