I have the code below on a tomcat server. The goal is to save in .jpg an image (that is sent in String) and create the equivalent thumbnails.
The goal is properly achieved nevertheless I noticed that at every execution (even after trying to set almost all used variables "null"), the server memomy increases by 6 Megabytes which are never freed. Since I have a very small RAM's server, this is really problematic. By the way images sent are close to 30 kilobytes only.
public boolean saveImage(String picInString)
throws IOException {
byte[] bytes = null;
try {
bytes = Base64.decode(picInString);
} catch (Base64DecodingException e) {
e.printStackTrace(System.out);
}
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
Iterator<?> readers = ImageIO.getImageReadersByFormatName("png");
ImageReader reader = (ImageReader) readers.next();
Object source = bis;
ImageInputStream iis = ImageIO.createImageInputStream(source);
Graphics2D g2 = null;
try {
reader.setInput(iis, true);
ImageReadParam param = reader.getDefaultReadParam();
Image image = reader.read(0, param);
// got an image file
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null),
image.getHeight(null), BufferedImage.TYPE_INT_RGB);
// bufferedImage is the RenderedImage to be written
g2 = bufferedImage.createGraphics();
g2.drawImage(image, null, null);
ImageIO.write(bufferedImage, "jpg", new File("/image.jpg"));
ImageIO.write(Scalr.resize(MyImageClass.cropImage(bufferedImage), 100, 100),
"jpg", new File("/image_mini.jpg"));
bufferedImage.flush();
bufferedImage = null;
} catch (Exception e) {
e.printStackTrace(System.out);
} finally {
if (reader != null) {
reader.dispose();
}
if (g2 != null) {
g2.dispose();
}
bis.close();
iis.close();
reader = null;
bis = null;
iis = null;
}
return false;
}
Any help will be appreciated!
Someone gave me a clue to the answer but I am not able to see the comment anymore.
Actually, setting the variable "image" to null at the end of the process has solved the issue.
You shouldn't tame an image as it is. You should down sample it like it is done in android. Scaling is a must to prevent memory errors and exceptions. This SO questions is the solution to all your problems.
How to improve the performance of g.drawImage() method for resizing images
Related
I am attempting to perform a basic kernel convolution pass on an image using the BufferedImageOp package in java.awt.image. This is the code I have:
BufferedImage img = null;
File f = null;
//read image
try {
f = new File("keys.JPG");
img = ImageIO.read(f);
} catch (IOException e) {
System.out.println(e);
}
float[] gaussian = {
1/16f, 1/8f, 1/16f,
1/8f, 1/4f, 1/8f,
1/16f, 1/8f, 1/16f,
};
BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, gaussian));
BufferedImage dest = op.filter(img, null);
File outputfile = new File("image.jpg");
ImageIO.write(dest, "jpg", outputfile);
My code attempts to load the image keys.JPG and then convolve this image with the Gaussian blur kernel and save the image to the file image.jpg. When I run the code, it processes for a bit then terminates and saves the image successfully but when I compare the original and the new images, they are identical.
Looking online at some code examples, my code should work. Am I missing something?
Thanks
As #haraldK mentioned, my image was too large to notice a difference. The code works as expected.
I am writing a test process which will act as duplicate to original processors
My class will take a video file as input then generates frame related information
Java2DFrameConverter bufferedImgConverter = new Java2DFrameConverter();
String filePath = "Palivala.mp4";
File tsFile = new File(filePath);
FFmpegFrameGrabber ffmpegFrameGrabber = new FFmpegFrameGrabber(tsFile);
OpenCVFrameConverter matConverter = new OpenCVFrameConverter.ToMat();
ffmpegFrameGrabber.start();
try {
while ((frame = ffmpegFrameGrabber.grabFrame(false, true, true, false)) != null) {
BufferedImage bufferedImage = bufferedImgConverter.convert(frame);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try {
ImageIO.write(bufferedImage, "jpeg", buffer);
} catch (IOException e) {
e.printStackTrace();
}
byte frameAsBytes[] = buffer.toByteArray();
start = System.currentTimeMillis();
BufferedImage bufferedImage2 = ImageIO.read(new ByteArrayInputStream(frameAsBytes));
Mat mat = matConverter.convertToMat(bufferedImgConverter.convert(bufferedImage)); //problem is here, I explained problem at the bottom
if (mat.empty())
continue;
if (prevMat != null) {
// here I am generating required data and sending to the method which I want to test
}
prevMat = mat.clone();
numProcessedFrames++;
}
} catch (org.bytedeco.javacv.FrameGrabber.Exception e) {
System.out.println("Exception while grabbing frames for segment " + e);
}
ffmpegFrameGrabber.stop();
If I use initial BufferedImage object(bufferedImage) its working as expected but when I use converted BufferedImage object(bufferedImage2) its not working as expected i.e actually my process finds info about frozen frames, If the video is frozen for 20seconds
Its giving final output as 20seconds (if I use bufferedImage object)
Its giving final output as 14seconds (if I use bufferedImage2 object)
I am generating standard-deviation using mat object which is getting from
Mat mat = matConverter.convertToMat(bufferedImgConverter.convert(bufferedImage)); //it works fine
Mat mat = matConverter.convertToMat(bufferedImgConverter.convert(bufferedImage2)); its the problem
I am getting frozen-frame info using standard-deviation and my standard-deviation-threshold is 90
standard-deviation is continuously below 90 If I use bufferedImage object
standard-deviation is continuously below 90 till 6 seconds then for 1 frame I am getting standard-deviation value as [118.0, 118.0, 119.0] then next frame again below 90 If I use bufferedImage2 object
I have a network program that sends a stream of BufferedImages through a network using ImageIO.write(..), this is working as intended apart from sometimes the Image received on the other end will just be a series of small black and white squares for a long time, then it will eventually switch back to sending the actual images.
I can't find any help with this anywhere.
I'm using Java version 1.8.0_65, I send the image like so:
BufferedImage capture = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
BufferedImage newImage = new BufferedImage(capture.getWidth(), capture.getHeight(), BufferedImage.TYPE_4BYTE_ABGR_PRE);
newImage.createGraphics().drawImage(capture, 0, 0, newImage.getWidth(), newImage.getHeight(), null);
capture = newImage;
BufferedImage difference = null;
if (lastImage != null) {
difference = getDifferenceImage(capture, lastImage);
} else {
difference = capture;
}
long generated = System.currentTimeMillis() - start;
ImageIO.write(difference, "png", socket.getOutputStream());
socket.getOutputStream().flush();
Try this code:
public byte[] getCustomImageInBytes(BufferedImage originalImage) {
byte[] imageInByte = null;
try {
// convert BufferedImage to byte array
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(originalImage, "png", baos);
baos.flush();
imageInByte = baos.toByteArray();
baos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return imageInByte;
}
socket.getOutputStream().write(getCustomImageInBytes(difference));
socket.getOutputStream().flush();
I have been augmenting the QR scanning library Zxing to save a photo instantly upon scan. I was advised to do so within the onPreviewFrame method within PreviewCallback.java as thus:
public void onPreviewFrame(byte[] data, Camera camera) {
Point cameraResolution = configManager.getCameraResolution();
Handler thePreviewHandler = previewHandler;
YuvImage im = new YuvImage(data, ImageFormat.NV21, 1200,
800, null);
Rect r = new Rect(0, 0, 1200, 800);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
im.compressToJpeg(r, 50, baos);
try {
FileOutputStream output = new FileOutputStream("/sdcard/test_jpg.jpg");
output.write(baos.toByteArray());
output.flush();
output.close();
System.out.println("Attempting to save file");
System.out.println(data);
} catch (FileNotFoundException e) {
System.out.println("Saving to file failed");
} catch (IOException e) {
System.out.println("Saving to file failed");
}
if (cameraResolution != null && thePreviewHandler != null) {
Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
cameraResolution.y, data);
message.sendToTarget();
previewHandler = null;
} else {
Log.d(TAG, "Got preview callback, but no handler or resolution available");
}}
The result of running this code is a corrupt image at the set file directory. I believe this is due to the code being run every frame. Is there a way to limit this to every second or so if that will allow the full image to save, or is there a method I can use to cause the image to only save upon completed scan.
I have a less favourable working alternative, in that I can successfully save the black and white image that is shown upon scan; colour is the preferable option of course.
Update: Code changed to (in theory) accommodate camera resolution on any device. Image is still corrupt.
public void onPreviewFrame(byte[] data, Camera camera) {
Point cameraResolution = configManager.getCameraResolution();
Handler thePreviewHandler = previewHandler;
android.hardware.Camera.Parameters parameters = camera.getParameters();
android.hardware.Camera.Size size = parameters.getPictureSize();
int height = size.height;
int width = size.width;
YuvImage im = new YuvImage(data, ImageFormat.NV21, width,
height, null);
Rect r = new Rect(0, 0, width, height);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
im.compressToJpeg(r, 50, baos);
try {
FileOutputStream output = new FileOutputStream("/sdcard/test_jpg.jpg");
output.write(baos.toByteArray());
output.flush();
output.close();
System.out.println("Attempting to save file");
System.out.println(data);
} catch (FileNotFoundException e) {
System.out.println("Saving to file failed");
} catch (IOException e) {
System.out.println("Saving to file failed");
}
if (cameraResolution != null && thePreviewHandler != null) {
Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
cameraResolution.y, data);
message.sendToTarget();
previewHandler = null;
} else {
Log.d(TAG, "Got preview callback, but no handler or resolution available");
}}
Having checked the width and height variable are correctly set to the Nexus 7's camera width and height of 1280x960. I am confident the issue comes from attempting to save the image every frame, as "Attempting to save to file" appears somewhat rapidly within the logcat; several times a second. It may also be worth noting that the corrupt image saved is square(ish).
Thanks in advance.
1200 x 800? are you sure this is your preview size? check your parameters. Probably it's 1280 x 720
I have created a graphical image with the following sample code.
BufferedImage bi = new BufferedImage(50,50,BufferedImage.TYPE_BYTE_BINARY);
Graphics2D g2d = bi.createGraphics();
// Draw graphics.
g2d.dispose();
// BufferedImage now has my image I want.
At this point I have BufferedImage which I want to convert into an IMG Data URI. Is this possible? For example..
<IMG SRC="data:image/png;base64,[BufferedImage data here]"/>
Not tested, but something like this ought to do it:
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(bi, "PNG", out);
byte[] bytes = out.toByteArray();
String base64bytes = Base64.encode(bytes);
String src = "data:image/png;base64," + base64bytes;
There are lots of different base64 codec implementations for Java. I've had good results with MigBase64.
You could use this solution which doesn't use any external libraries. Short and clean! It uses a Java 6 library (DatatypeConverter). Worked for me!
ByteArrayOutputStream output = new ByteArrayOutputStream();
ImageIO.write(image, "png", output);
DatatypeConverter.printBase64Binary(output.toByteArray());
I use Webdriver, get captcha, like this below:
// formatName -> png
// pathname -> C:/Users/n/Desktop/tmp/test.png
public static String getScreenshot(WebDriver driver, String formatName, String pathname) {
try {
WebElement element = driver.findElement(By.xpath("//*[#id=\"imageCodeDisplayId\"]"));
File screenshot = element.getScreenshotAs(OutputType.FILE);
// base64 data
String base64Str = ImageUtil.getScreenshot(screenshot.toString());
return base64Str;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String getScreenshot(String imgFile) {
InputStream in;
byte[] data = null;
try {
in = new FileInputStream(imgFile);
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
String base64Str = new String(Base64.getEncoder().encode(data));
if (StringUtils.isAnyBlank(base64Str)) {
return null;
}
if (!base64Str.startsWith("data:image/")) {
base64Str = "data:image/jpeg;base64," + base64Str;
}
return base64Str;
}