Swing - Images in Jpanel looks blurry on large screens - java

There is a logo image displayed on Login screen inside JPanel. This image looks blurry on large monitor screens. Can anybody tell me how to fix the issue of blurred images, so that images looks sharp and clear on large monitor screens ?
Do I have to make high resolution images and scale down according to screen size ?
Below is the method to resize images in proportion.
public ImagePanel(String url, int w, int h) {
try {
InputStream is = getFileFromResourceAsStream(url);
image = ImageIO.read(is);
imageurl = url;
width=w;
height=h;
isscaled = true;
outputImage = new BufferedImage(w,h, image.getType());
} catch (IOException ex) {
ex.printStackTrace();
}
}
Here how to calculate the new height and width to be passed as parameter according to screen size ?
Thank you.

Related

iText 7 SVG as a background

I'm trying to add a background in a PDF using Scalable Vector Graphics (.svg). Initially the recommended way was to transform the SVG into an Image object and then use scaleToFit to get it to the right size, then add it to the document. This works partially as it transforms the small and scalable SVG into a Bitmap. Next I've made a PdfFormXObject in order to get back the scaling by having it drawn on each page. However, now it does not display anything at all.
ByteArrayInputStream inputStream = new ByteArrayInputStream(backgroundBytes);
PdfFormXObject svg = SvgConverter.convertToXObject(inputStream, pdf);
PdfCanvas canvas = new PdfCanvas(pdf.getFirstPage());
Rectangle rect = new Rectangle(PageSize.A4.getWidth(), PageSize.A4.getHeight());
canvas.addXObject(svg, rect);
How should I be adding SVG backgrounds to iText 7 PDFs? Can this be done properly in the first place? I have not been able to find good code examples.
Update:
Here is the code for converting the SVG to a properly scaled Image. The issue with this is that it works for adding the image, but it adds it as an element so it pushes everything else down.
ByteArrayInputStream inputStream = new ByteArrayInputStream(svgAsBytes);
Image image = SvgConverter.convertToImage(inputStream, pdf);
image.scaleAbsolute(PageSize.A4.getWidth(), PageSize.A4.getHeight());
int totalPages = pdf.getNumberOfPages()+1;
for(int pageNumber = 1; pageNumber < totalPages; pageNumber++ ) {
document.add(image);
}
Hi i have a similar Problem. I am trying to add a SVG image as a table cell background. The problem is that i can not scale the image. Here is my code:
InputStream triangleSteam = this.getClass().getResourceAsStream("/AH-AddressTriangle.svg");
Image triangle = SvgConverter.convertToImage(triangleSteam, pdfDocument);
//triangle.setHeight(UnitValue.createPointValue(127.83f));
//triangle.setWidth(UnitValue.createPointValue(78.63f));
triangle.scaleAbsolute(78.63f, 127.83f);
Cell headerCell_12 = new Cell();
headerCell_12.setBorder(Border.NO_BORDER);
headerCell_12.setPadding(0f);
headerCell_12.setHeight(UnitValue.createPointValue(127.83f));
headerCell_12.setWidth(UnitValue.createPointValue(78.63f));
headerCell_12.setNextRenderer(new ImageBackgroundCellRenderer(headerCell_12, triangle));
headerTable.addCell(headerCell_12);
And here ist the BackgroundCellRenderer I am using:
protected class ImageBackgroundCellRenderer extends CellRenderer {
Image img;
public ImageBackgroundCellRenderer(Cell modelElement, Image img) {
super(modelElement);
this.img = img;
}
#Override
public IRenderer getNextRenderer() {
return new ImageBackgroundCellRenderer((Cell) modelElement, img);
}
#Override
public void draw(DrawContext drawContext) {
try {
img.scaleToFit(getOccupiedAreaBBox().getWidth(), getOccupiedAreaBBox().getHeight());
drawContext.getCanvas().addXObject(img.getXObject(), getOccupiedAreaBBox());
super.draw(drawContext);
} catch(Exception e) {
e.printStackTrace();
}
}
}
The background is added but the image is not scaled (see picture)
Screenshot from Adobe Illustrator
The SVG becomes even bigger that it actually was!
Thank you!

Java Image Processing: Why is the output image smaller in storage than the input image?

I'm learning Java Image Processing. Here is my code:
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class LoadImage {
public static void main(String[] args) {
int width = 1280;
int height = 720;
BufferedImage image = null;
// READ IMAGE
try {
File input_image = new File("E:\\SELF-TAUGHT LEARNING\\39. Image Processing with Java\\test-image.jpg");
image = new BufferedImage (width,height,BufferedImage.TYPE_INT_ARGB);
image = ImageIO.read(input_image);
System.out.println("Read successfully");
}
catch (IOException e) {
System.out.println("Error: " + e);
}
// WRITE IMAGE
try {
File output_image = new File("E:\\SELF-TAUGHT LEARNING\\39. Image Processing with Java\\test-image-output.jpg");
ImageIO.write(image, "jpg", output_image);
System.out.println("Writing successfully");
}
catch (IOException e) {
System.out.println("Error: "+ e);
}
}
}
So the input image is around 300kb. But the output image is only 48kb. Why? Thank you
If the image is the same resolution and quality after saving the new version, it's likely just a difference of metadata and formatting. It's also possible, however, that you are getting a lower quality image - if the original image had a high enough quality setting, it may not be noticeable when Java saves it at a lower quality.
Some things to check:
do the before and after images look different?
is the after image smaller in size?
I'm not very knowledgeable about Java, and don't know a lot about their image processing, but I would imagine there are methods for setting image size, resolution, and quality. I do, however, work with images a lot, and I know there are a lot of optimizations (especially in JPEG images) that you can do to reduce file size without affecting visual quality noticeably.

Cropping BufferedImage For Use in Xuggle encodeVideo

I have an application to capture video of the screen and save to a file. I give the user the ability to pick between 480, 720, and "Full Screen" video sizes. A 480 will record in a small box on the screen, 720 will record in a larger box, and of course, "Full Screen" will record in an even larger box. However, this full screen box is NOT the actual screen resolution. It is the app window size, which happens to be around 1700x800. The Video Tool works perfectly for the 480 and 720 options, and will also work if "Full Screen" is overwridden to be the entire screen of 1920x1080.
My question: Are only certain sizes allowed? Does it have to fit a certain aspect ratio, or be an "acceptable" resolution? My code, below, is modified from the xuggle CaptureScreenToFile.java file (the location of the problem is noted by comments):
public void run() {
try {
String parent = "Videos";
String outFile = parent + "example" + ".mp4";
file = new File(outFile);
// This is the robot for taking a snapshot of the screen. It's part of Java AWT
final Robot robot = new Robot();
final Rectangle customResolution = where; //defined resolution (custom record size - in this case, 1696x813)
final Toolkit toolkit = Toolkit.getDefaultToolkit();
final Rectangle fullResolution = new Rectangle(toolkit.getScreenSize()); //full resolution (1920x1080)
// First, let's make a IMediaWriter to write the file.
final IMediaWriter writer = ToolFactory.makeWriter(outFile);
writer.setForceInterleave(false);
// We tell it we're going to add one video stream, with id 0,
// at position 0, and that it will have a fixed frame rate of
// FRAME_RATE.
writer.addVideoStream(0, 0, FRAME_RATE, customResolution.width, customResolution.height); //if I use fullResolution, it works just fine - but captures more of the screen than I want.
// Now, we're going to loop
long startTime = System.nanoTime();
while (recording) {
// take the screen shot
BufferedImage screen = robot.createScreenCapture(fullResolution); //tried capturing using customResolution, but did not work. Instead, this captures full screen, then tries to trim it below (also does not work).
// convert to the right image type
BufferedImage bgrScreen = convertToType(screen, BufferedImage.TYPE_3BYTE_BGR); //Do I need to convert after trimming?
BufferedImage trimmedScreen = bgrScreen.getSubimage((int)customResolution.getX(), (int)customResolution.getY(), (int)customResolution.getWidth(), (int)customResolution.getHeight());
// encode the image
try{
//~~~~Problem is this line of code!~~~~ Error noted below.
writer.encodeVideo(0, trimmedScreen, System.nanoTime() - startTime, TimeUnit.NANOSECONDS); //tried using trimmedScreen and bgrScreen
} catch (Exception e) {
e.printStackTrace();
}
// sleep for framerate milliseconds
Thread.sleep((long) (1000 / FRAME_RATE.getDouble()));
}
// Finally we tell the writer to close and write the trailer if
// needed
writer.close();
} catch (Throwable e) {
System.err.println("an error occurred: " + e.getMessage());
}
}
public static BufferedImage convertToType(BufferedImage sourceImage, int targetType) {
BufferedImage image;
// if the source image is already the target type, return the source image
if (sourceImage.getType() == targetType)
image = sourceImage;
// otherwise create a new image of the target type and draw the new image
else {
image = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), targetType);
image.getGraphics().drawImage(sourceImage, 0, 0, null);
}
return image;
}
Error:
java.lang.RuntimeException: could not open stream com.xuggle.xuggler.IStream#2834912[index:0;id:0;streamcoder:com.xuggle.xuggler.IStreamCoder#2992432[codec=com.xuggle.xuggler.ICodec#2930320[type=CODEC_TYPE_VIDEO;id=CODEC_ID_H264;name=libx264;];time base=1/50;frame rate=0/0;pixel type=YUV420P;width=1696;height=813;];framerate:0/0;timebase:1/90000;direction:OUTBOUND;]: Operation not permitted
Note: The file is successfully created, but has size of zero, and cannot be opened by Windows Media Player, with the following error text:
Windows Media Player cannot play the file. The Player might not support the file type or might not support the codec that was used to compress the file.
Sorry for the wordy question. I'm interested in learning WHAT and WHY, not just a solution. So if anyone can explain why it isn't working, or point me towards material to help, I'd appreciate it. Thanks!
Try to have the dimension even numbers 1696x812

take snapshot of full JFrame and Jframe only [duplicate]

This question already has an answer here:
Swing: Obtain Image of JFrame
(1 answer)
Closed 7 years ago.
Heys guys, I've developped a code to take a screen shot of my whole screen, but I want it to take the screen shot of only the things inside my Jframe. Ill be using it to print the image later on by the way. And one of the main problem is, the mouse also comes inside the snapshot. I don't want the mouse or the two buttons at the bottom. I can just change visi of buttons but what should be done for mouse and inside Jframe only shot? Here is my code it takes screen shot of whole screen.
try{
Thread.sleep(1000);
Toolkit tk = Toolkit.getDefaultToolkit(); //Toolkit class returns the default toolkit
Dimension d = tk.getScreenSize();
//Dimension class object stores width & height of the toolkit screen
// toolkit.getScreenSize() determines the size of the screen
Rectangle rec = new Rectangle(0, 0, d.width, d.height);
//Creates a Rectangle with screen dimensions,
Robot ro = new Robot(); //to capture the screen image
BufferedImage img = ro.createScreenCapture(rec);
File f;
f = new File("myimage.jpg"); // File class is used to write the above generated buffered image to a file
ImageIO.write(img, "jpg", f);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
IMHO it is better to make an image of your component (a JFrame is also a Component):
BufferedImage img = new BufferedImage(yourComponent.getWidth(), yourComponent.getHeight(), BufferedImage.TYPE_INT_RGB);
yourComponent.paint(img.getGraphics());
File outputfile = new File("saved.png");
ImageIO.write(img, "png", outputfile);

Java BufferedImage alternatives

I am trying to implement a simple class that will allow a user to crop an image to be used for their profile picture. This is a java web application.
I have done some searching and found that java.awt has a BufferedImage class, and this appears (at first glance) to be perfect for what I need. However, it seems that there is a bug in this (or perhaps java, as I have seen suggested) that means that the cropping does not always work correctly.
Here is the code I am using to try to crop my image:
BufferedImage profileImage = getProfileImage(form, modelMap);
if (profileImage != null) {
BufferedImage croppedImage = profileImage
.getSubimage(form.getStartX(), form.getStartY(), form.getWidth(), form.getHeight());
System.err.println(form.getStartX());
System.err.println(form.getStartY());
File finalProfileImage = new File(form.getProfileImage());
try {
String imageType = getImageType(form.getProfileImage());
ImageIO.write(croppedImage, imageType, finalProfileImage);
}
catch (Exception e) {
logger.error("Unable to write cropped image", e);
}
}
return modelAndView;
}
protected BufferedImage getProfileImage(CropImageForm form, Map<String, Object> modelMap) {
String profileImageFileName = form.getProfileImage();
if (validImage(profileImageFileName) && imageExists(profileImageFileName)) {
BufferedImage image = null;
try {
image = getCroppableImage(form, ImageIO.read(new File(profileImageFileName)), modelMap);
}
catch (IOException e) {
logger.error("Unable to crop image, could not read profile image: [" + profileImageFileName + "]");
modelMap.put("errorMessage", "Unable to crop image. Please try again");
return null;
}
return image;
}
modelMap.put("errorMessage", "Unable to crop image. Please try again.");
return null;
}
private boolean imageExists(String profileImageFileName) {
return new File(profileImageFileName).exists();
}
private BufferedImage getCroppableImage(CropImageForm form, BufferedImage image, Map<String, Object> modelMap) {
int cropHeight = form.getHeight();
int cropWidth = form.getWidth();
if (cropHeight <= image.getHeight() && cropWidth <= image.getWidth()) {
return image;
}
modelMap.put("errorMessage", "Unable to crop image. Crop size larger than image.");
return null;
}
private boolean validImage(String profileImageFileName) {
String extension = getImageType(profileImageFileName);
return (extension.equals("jpg") || extension.equals("gif") || extension.equals("png"));
}
private String getImageType(String profileImageFileName) {
int indexOfSeparator = profileImageFileName.lastIndexOf(".");
return profileImageFileName.substring(indexOfSeparator + 1);
}
The form referred to in this code snippet is a simple POJO which contains integer values of the upper left corner to start cropping (startX and startY) and the width and height to make the new image.
What I end up with, however, is a cropped image that always starts at 0,0 rather than the startX and startY position. I have inspected the code to make sure the proper values are being passed in to the getSubimage method, and they appear to be.
Are there simple alternatives to using BufferedImage for cropping an image. I have taken a brief look at JAI. I would rather add a jar to my application than update the jdk installed on all of the production boxes, as well as any development/testing servers and local workstations.
My criteria for selecting an alternative are:
1) simple to use to crop an image as this is all I will be using it for
2) if not built into java or spring, the jar should be small and easily deployable in a web-app
Any suggestions?
Note: The comment above that there is an issue with bufferedImage or Java was something I saw in this posting: Guidance on the BufferedImage.getSubimage(int x, int y, int w, int h) method?
I have used getSubimage() numerous times before without any problems. Have you added a System.out.println(form.getStartX() + " " + form.getStartY()) before that call to make sure they're not both 0?
Also, are you at least getting an image that is form.getWidth() x form.getHeight()?
Do make sure you are not modifying/disposing profileImage in any way since the returned BufferedImage shares the same data array as the parent.
The best way is to just simply draw it across if you want a completely new and independent BufferedImage:
BufferedImage croppedImage = new BufferedImage(form.getWidth(),form.getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics g = croppedImage.getGraphics();
g.drawImage(profileImage,0,0,form.getWidth(),form.getHeight(),form.getStartX(),form.getStartY(),form.getWidth(),form.getHeight(),null);
g.dispose();
You can do it in this manner as well (code is not 100% tested as I adopted for example from an existing app i did):
import javax.imageio.*;
import java.awt.image.*;
import java.awt.geom.*;
...
BufferedImage img = ImageIO.read(imageStream);
...
/*
* w = image width, h = image height, l = crop left, t = crop top
*/
ColorModel dstCM = img.getColorModel();
BufferedImage dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(w, h), dstCM.isAlphaPremultiplied(), null);
Graphics2D g = dst.createGraphics();
g.drawRenderedImage(img, AffineTransform.getTranslateInstance(-l,-t));
g.dispose();
java.io.File outputfile = new java.io.File(sessionScope.get('absolutePath') + java.io.File.separator + sessionScope.get('lastUpload'));
ImageIO.write(dst, 'png', outputfile);
Thanks for all who replied. It turns out that the problem was not in the cropping code at all.
When I displayed the image to be cropped, I resized it to fit into my layout nicely, then used a javascript cropping tool to figure out the coordinates to crop.
Since I had resized my image, but didn't take the resizing into account when I was determining the cropping coordinates, I ended up with coordinates that appeared to coincide with the top left corner.
I have changed the display to no longer resize the image, and now cropping is working beautifully.

Categories