I want to read an image to scale it using awt and Apache Commons Imaging, previously known as Apache Commons Sanselan
I can not scale the image but I can see it in the browser properly as jpg without any problem.
Getting the image info using
Sanselan.getMetadata(fileData)
I get this info:
No Exif metadata.
Photoshop (IPTC) metadata:
The code
public static byte[] scale(byte[] fileData, int width, int height) {
ByteArrayInputStream in = new ByteArrayInputStream(fileData);
try {
BufferedImage img = javax.imageio.ImageIO.read(in);
....
return buffer.toByteArray();
} catch (IOException e1) {
System.out.println ("e1 -> " + e1.getMessage());
try {
BufferedImage img = Sanselan.getBufferedImage(in);
} catch (ImageReadException | IOException e2) {
System.out.println ("e2 -> " + e2.getMessage());
}
}
return fileData;
}
but I got this exceptions:
e1 -> Unsupported Image Type
e2 -> Can't parse this format.
Image scaling can be done without external libraries.
Image img = ImageIO.read(URL);
Image scaledImg = img.getScaledInstance(IMG_WIDTH, IMG_HEIGHT, Image.SCALE_DEFAULT);
See the docs for further inspiration.
Related
This example uses a file which most likely resides not in RAM:
http://docs.aws.amazon.com/AmazonS3/latest/dev/UploadObjSingleOpJava.html
but I already got a buffered file from a certain client request and in the code below, this file gets written to disk, but why ? it makes the whole process slow by writing to disk, can't I avoid it?
EDIT (Below is explanation of what I am trying to achieve):
A user's image is uploaded then scaled by the server and then saved on the server's disk and only then this scaled image is sent to AWS, afterwards the user gets an aws link where the image resides on the amazon server.
public void transferToS3(String region, String bucket, String entity, String resolution, String filename, BufferedImage bufferedImage) {
if (bufferedImage != null) {
String objectpath = "/" + "images" + "/" + entity + "/" + resolution + "/" + filename + "." + "png";
Path tmpFile = null;
try {
tmpFile = Files.createTempFile(imagesPath, "tmp_", ".png");
} catch (IOException e) {
e.printStackTrace();
}
tmpFile.toFile().deleteOnExit();
try {
ImageIO.write(bufferedImage, "png", tmpFile.toFile());
S3AsyncClient client = S3AsyncClient.builder().region(Region.of(region)).build();
CompletableFuture<PutObjectResponse> future =
client.putObject(PutObjectRequest.builder()
.bucket(bucket)
.key(objectpath)
.contentType("image/png")
.build(),
AsyncRequestProvider.fromFile(tmpFile.toAbsolutePath()));
Path finalTmpFile = tmpFile;
future.whenComplete((resp, err) -> {
try {
if (resp != null) {
logger.debug(resp.toString());
} else {
logger.error(err.toString());
}
Files.deleteIfExists(finalTmpFile.toAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
} finally {
FunctionalUtils.invokeSafely(client::close);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
Scaling routine returns a scaled BufferedImage which is then used in the transferToS3 method.
public BufferedImage scale(int width, int height, BufferedImage bufferedImage) {
BufferedImage scaledBufferedImage = null;
if (bufferedImage != null) {
Image image = bufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
scaledBufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
scaledBufferedImage.getGraphics().drawImage(image, 0, 0, null);
}
return scaledBufferedImage;
}
The 2 above together:
BufferedImage scaledBufferedImage = imageService.scale(width, height finalBufferedImage);
imageService.transferToS3(region, bucket, name, k, file, scaledBufferedImage);
You can do whatever you wish with the data stream from the request. Feel free to scale the image in memory and send it back in the response. The example you linked writes the file to disk because this is by far the most common scenario. It also allows the author to focus on the details of uploading a file without polluting the example with unrelated code.
Note that bufferedImage is not a file. It is a stream. I suspect the author saved the image to disk in order to avoid assuming anything about the size of the image. If the image is too large to fit in RAM, then you will have difficulties doing the scaling in memory.
I am trying to read the dimensions of a PNG image, but I encounter the below error while doing so -
Exception in thread "main" javax.imageio.IIOException: I/O error reading PNG header!
at com.sun.imageio.plugins.png.PNGImageReader.readHeader(PNGImageReader.java:307)
at com.sun.imageio.plugins.png.PNGImageReader.readMetadata(PNGImageReader.java:637)
at com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1212)
at com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1560)
at javax.imageio.ImageIO.read(ImageIO.java:1422)
at javax.imageio.ImageIO.read(ImageIO.java:1326)
Here is the code I have that's causing it -
InputStream is = new ByteArrayInputStream(myImgByteArray);
BufferedImage image = ImageIO.read(is);
System.out.println("Height: " +image.getHeight()+ "Width: " +image.getWidth());
Can someone please suggest what I need to do to fix this?
You may user the other way to get the image dimensions:
BufferedImage image = javax.imageio.ImageIO.read(new File(imageFilePath));
System.out.println(image.getHeight());
System.out.println(image.getWidth());
It depends on how are you constructing myImgByteArray. Try this one.
BufferedImage image = ImageIO.read(new FileInputStream((new File("resources/1.png"))));
System.out.println("Height: " + image.getHeight() + "Width: " + image.getWidth());
You can try any one
// Read from same package
ImageIO.read(getClass().getResourceAsStream("c.png"));
// Read from absolute path
ImageIO.read(new File("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\c.png"));
// Read from images folder parallel to src in your project
ImageIO.read(new File("images\\c.jpg"));
Probably there is something wrong when u load the image in the BuggeredImage. He is my test code.
BufferedImage image = null;
try {
image = ImageIO.read(new File("/home/adrian/Documents/wave.png"));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Height: " +image.getHeight()+ " Width: " +image.getWidth());
This is the output:
Height: 1170 Width: 2576
BUILD SUCCESSFUL (total time: 0 seconds)
Show us how u get the myImgByteArray so we can see if there is an error before.
You could try like this:
public LoadImageApp() {
try {
img = ImageIO.read(new File("/workspace/ImageProject/src/myPic.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
public Dimension getPreferredSize() {
if (img == null) {
return new Dimension(100,100);
} else {
System.out.println("Height: " +img.getHeight()+ " Width: " +img.getWidth());
return new Dimension(img.getWidth(null), img.getHeight(null));
}
}
Make sure you are calling the file location correctly! In Linux your path has to be in this format :
/path/to/my/file.png
while in Windows, this is the path to the file:
C:\\workspace\\path\to\myFile.png
I am a beginner in java, and I am trying to write a simple screen-capture program. I wrote a simple SWING desktop app with a button and a text-field, and what I am trying to do is, when a user clicks that button the app takes a snapshot of the screen using awt.Robot, and sends that image and the text to a PHP script on my server.
My snapshot function so far is:
private void takeSnapShot(){
try {
Robot robot = new Robot();
Rectangle area = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage bufferedImage = robot.createScreenCapture(area);
//Try to save the captured image
try {
File file = new File("screenshot_full.png");
ImageIO.write(bufferedImage, "png", file);
} catch (IOException ex) {
Logger.getLogger(ScrCaptFrm.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (AWTException ex) {
Logger.getLogger(ScrCaptFrm.class.getName()).log(Level.SEVERE, null, ex);
}
}
As you can see it's fairly simple so far, however I am not sure how to send that image to my PHP script without actually storing the image on user's PC.
Oh and I am using apache httpClient library for communicating to the web server. For the text I guess I can pass it in the URL as a get query, but I am not sure what to do about the image.
ImageIO.write can to an OutputStream of your choice.
So if you don't want to write the image to a File, you can simply write it to a different stream instead...
For example...
OutputStream os = null;
try {
Robot robot = new Robot();
Rectangle area = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage bufferedImage = robot.createScreenCapture(area);
//Try to save the captured image
try {
os = ...;
ImageIO.write(bufferedImage, "png", os);
} catch (IOException ex) {
Logger.getLogger(ScrCaptFrm.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
os.close();
} catch (Exception exp) {
}
}
} catch (AWTException ex) {
Logger.getLogger(ScrCaptFrm.class.getName()).log(Level.SEVERE, null, ex);
}
Of course, I have no idea where you're sending the data, so you'll need to define the OutputStream yourself.
If you have the memory for it, you could write it a ByteArrayOutputStream and then write this to whatever output stream you need in the future...
To slightly modify your existing method, perhaps you could use a temporarily file and then delete it when you are finished with it. Perhaps it might look something like:
private void takeSnapShot(){
try {
Robot robot = new Robot();
Rectangle area = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage bufferedImage = robot.createScreenCapture(area);
//Try to save the captured image
try {
File file = File.createTempFile(Long.toString(System.currentTimeMillis()), ".png");
ImageIO.write(bufferedImage, "png", file);
//send image
file.delete();
} catch (IOException ex) {
Logger.getLogger(ScrCaptFrm.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (AWTException ex) {
Logger.getLogger(ScrCaptFrm.class.getName()).log(Level.SEVERE, null, ex);
}
}
Another alternative would be to construct an int[][] from your BufferedImage which will hold the RGB values for every pixel of the image:
public int[][] getColors(final BufferedImage image){
assert image != null;
final int[][] colors = new int[image.getWidth()][image.getHeight()];
for(int x = 0; x < colors.length; x++)
for(int y = 0; y < colors[x].length; y++)
colors[x][x] = image.getRGB(x, y);
return colors;
}
I am a little unsure about what you hope to achieve; What do you plan on doing with the image?
Why don't you make this a WebsService and let your PHP consume it? You could send the binary data through the WebsService using some sort of Base64 encoder.
You could do this to get the bytes of the BufferedImage:
byte[] binaryData = ((DataBufferByte) bufferedImage.getData().getDataBuffer()).getData();
I am using below code to convert PDF to PNG image.
Document document = new Document();
try {
document.setFile(myProjectPath);
System.out.println("Parsed successfully...");
} catch (PDFException ex) {
System.out.println("Error parsing PDF document " + ex);
} catch (PDFSecurityException ex) {
System.out.println("Error encryption not supported " + ex);
} catch (FileNotFoundException ex) {
System.out.println("Error file not found " + ex);
} catch (IOException ex) {
System.out.println("Error handling PDF document " + ex);
}
// save page caputres to file.
float scale = 1.0f;
float rotation = 0f;
// Paint each pages content to an image and write the image to file
InputStream fis2 = null;
File file = null;
for (int i = 0; i < 1; i++) {
BufferedImage image = (BufferedImage) document.getPageImage(i,
GraphicsRenderingHints.SCREEN,
Page.BOUNDARY_CROPBOX, rotation, scale);
RenderedImage rendImage = image;
// capture the page image to file
try {
System.out.println("\t capturing page " + i);
file = new File(myProjectActualPath + "myImage.png");
ImageIO.write(rendImage, "png", file);
fis2 = new BufferedInputStream(new FileInputStream(myProjectActualPath + "myImage.png"));
} catch (IOException ioe) {
System.out.println("IOException :: " + ioe);
} catch (Exception e) {
System.out.println("Exception :: " + e);
}
image.flush();
}
myProjectPath is the path of the pdf file.
The problem is that I have pdf image of size 305 KB. When I use above code to convert image, the image size is 5.5 MB which is unexpected. Any reason why this is happening? Is there way to compress this? If I get solution to compress the size (by making down the pixel size), it is also OK.
Note : For other pdf files, images are coming to 305 KB. This is happening with one PDF file and not sure why this is happening.
Edit 1
I am using jar files as
icepdf-core.jar
icepdf-viewer.jar
The import that I have are
import org.icepdf.core.exceptions.PDFException;
import org.icepdf.core.exceptions.PDFSecurityException;
import org.icepdf.core.pobjects.Document;
import org.icepdf.core.pobjects.Page;
import org.icepdf.core.util.GraphicsRenderingHints;
You could extract the images from the pdf (example using PDFBox):
List<PDPage> pages = document.getDocumentCatalog().getAllPages();
for(PDPage page : pages) {
Map<String, PDXObjectImage> images = page.getResources().getImages();
for(PDXObjectImage image : images.values()){
//TODO: write image to disk
}
}
OR/AND you may want to save them as jpg to disk, as jpg overs compression as opposed to png.
You could even identify the format of the orignal image and use that when writing to disk by calling:
image.getSuffix();
You should be able to change the size of the file by changing scale. PDFs are often much smaller then rendered images. They can represent text and vector graphics which the rendered image will use a lot of bytes to represent. I'm actually somewhat surprised that any of your pngs are about the same size as the pdfs (unless the pdfs are just pictures).
I am trying to convert a PNG image to a JPEG image following this tutorial. But I encounter a problem. The resulting image has a pink layer.
Does anyone have a solution for this problem? Or what code should I use in order to convert the image into the desired format?
Thanks in advance!
Create a BufferedImage of desired size, e.g.:
BufferedImage img = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB)
fill it with a proper background color:
img.getGraphics().fillRect(....)
Call drawImage on the image's graphics atop of that background:
img.getGraphics().drawImage(image, 0, 0, null);
then write down your image as JPG as usual.
Which color mode are you using? While you create buffered image object, try adding the type like this option.
File newFile = new File(path + fileName + "." + Strings.FILE_TYPE);
Image image = null;
try {
image = ImageIO.read(url); // I was using an image from web
} catch (IOException e1) {
e1.printStackTrace();
}
image = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
try {
BufferedImage img = toBufferedImage(image);
ImageIO.write(img, "jpg", newFile);
} catch (IOException e) {
e.printStackTrace();
}
}
private static BufferedImage toBufferedImage(Image src) {
int w = src.getWidth(null);
int h = src.getHeight(null);
int type = BufferedImage.TYPE_INT_RGB; // other options
BufferedImage dest = new BufferedImage(w, h, type);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(src, 0, 0, null);
g2.dispose();
return dest;
}