I am creating a game of space invaders and i would like for all of the images to be in ratio to the screen resolution. This means that it can be used on all screen sizes and all the images will shrink or get bigger so that they fit onto the screen. The game is fullscreen. What is the easiest technique to do this? Also is this the best way to set the size of everything?
Have you had a look at Image#getScaledInstance() though it has its downfalls(The Perils of Image.getScaledInstance()) in short the problem is:
Image.getScaledInstance() does not return a finished, scaled image. It
leaves much of the scaling work for a later time when the image pixels
are used.
due to these downfalls you might want a different way to resize your images, you could try something like this:
import javax.swing.ImageIcon;
import java.awt.image.BufferedImage;
import java.awt.Image;
import java.awt.Color;
import java.awt.Graphics2D;
import java.io.File;
import javax.imageio.ImageIO;
import java.awt.RenderingHints;
public class ImgUtils {
public BufferedImage scaleImage(int WIDTH, int HEIGHT, String filename) {
BufferedImage bi = null;
try {
ImageIcon ii = new ImageIcon(filename);//path to image
bi = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(ii.getImage(), 0, 0, WIDTH, HEIGHT, null);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return bi;
}
}
you'd use it like:
BufferedImage img=new ImgUtils().scaleImage(50,50,"c:/test.jpg");
//now you have a scaled image in img
References:
resizing image java getScaledInstance
Suppose g is your instance of the Graphics2D object, and theImage is the Image you want to draw, and xFactor and yFactor are the scaling factors for x and y, try:
AffineTransformation scaleTransformation = AffineTransformation.getScaleInstance(xFactor, yFactor);
g.draw(theImage, scaleTransformation, null);
Image getScaledImage(Image Img, int wt, int ht) {
BufferedImage resizedImg = new BufferedImage(wt, ht, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(Img, 0, 0, wt, ht, null);
g2.dispose();
return resizedImg;
}
Related
Java JLabel icons are displaying with distorted pixels in JFrame. This is happening consistently with different png images (all 32x32). I am not scaling the images, they are displayed in the program 32x32, which I verified using getWidth and getHeight on the JLabel. The distortions appear in the same place each time the program is run, not randomly.
Screenshot using the example code provided below.
In this screenshot you can see an array of JLabel icons, each affected one differently.
When resizing the window from sideways, as the icon moves with the window, the distortions move across the icon like a vertical line.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
public class FrameApp extends JFrame
{
public static void main(String[] args) throws IOException
{
FrameApp frameApp = new FrameApp();
}
private FrameApp() throws IOException
{
BufferedImage image;
URL url = new URL("http://i.stack.imgur.com/L5DGx.png");
image = ImageIO.read(url);
JLabel label = new JLabel(new ImageIcon(image));
add(label);
pack();
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
Edit:
I am using JDK 11.0.3, Java SE Runtime Environment build 1.8.0_202, on Windows 8.1 64-bit.
You may think you're displaying the images at 32x32 size, but your example of the tiled images says that's not so. You have a 9x2 grid of icons, which should be 288x64 pixels, but in your sample image the grid is 302x66.
If you carefully examine your tiled image, you can see that the individual tiles are being displayed 34px wide - see the magenta border that extends from 32px to 66px. (Note, some of the tiles are displayed 33px wide; it appears to be 33, 34, 34, 33, 34...)
In order to stretch the tiles to the wider width, certain columns are being doubled (red borders) and this creates the visual glitches you are seeing.
Have you tried fixing the size of the JLabel instead of allowing it to size based on its contents?
First option:
Instead of using ImageIcon, you can try to create your own icon class drawing the Image using graphics.drawImage(x,y,width,height,null) controlling rendering quality (https://docs.oracle.com/javase/tutorial/2d/advanced/quality.html)
an example would be something like this:
public class Icon32 extends ImageIcon {
public Icon32(String f) {
super(f);
BufferedImage i= new BufferedImage(32, 32,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) i.getGraphics();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(getImage(), 0, 0, 32, 32, null);
setImage(i);
}
public int getIconHeight() {
return 32;
}
public int getIconWidth() {
return 32;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.drawImage(getImage(), x, y, c);
}
}
where the method:
getImage()
is loading your image/icon...
Second option: if you are not happy with the result you can try to use this library:
https://github.com/mortennobel/java-image-scaling
it claims to provides better image scaling options than the Java runtime provides.
Answer is from this link to generate high quality image : https://componenthouse.com/2008/02/08/high-quality-image-resize-with-java/
The appropriate class from the link :
public class ImageResize {
public static void main(String[] args) {
try {
URL url = new URL("http://i.stack.imgur.com/L5DGx.png");
BufferedImage image = ImageIO.read(url);
ImageIO.write(resizeImage(image, 32, 32), "png", new File("D:/picture3.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
private static BufferedImage resize(BufferedImage image, int width, int height) {
int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(image, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
private static BufferedImage resizeImage(BufferedImage image, int width, int height) {
image = createCompatibleImage(image);
image = resize(image, 100, 100);
image = blurImage(image);
return resize(image, width, height);
}
public static BufferedImage blurImage(BufferedImage image) {
float ninth = 1.0f/9.0f;
float[] blurKernel = {
ninth, ninth, ninth,
ninth, ninth, ninth,
ninth, ninth, ninth
};
Map<RenderingHints.Key, Object> map = new HashMap<RenderingHints.Key, Object>();
map.put(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
map.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
map.put(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
RenderingHints hints = new RenderingHints(map);
BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
return op.filter(image, null);
}
private static BufferedImage createCompatibleImage(BufferedImage image) {
GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
int w = image.getWidth();
int h = image.getHeight();
BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
Graphics2D g2 = result.createGraphics();
g2.drawRenderedImage(image, null);
g2.dispose();
return result;
}
}
I created a class called VainillaImagen:
public VainillaImage(String url){
this.icimg=new ImageIcon(url);
this.imagen=new JLabel(this.icimg);
this.imagen.setVisible(true);
}
and then I created a methos called setDimensions that use another method called resizeVainillaImg. But the resizeVainillaImg method dont work any ideas why?
public void setDimensions(boolean wRel,int width,boolean hRel,int height){
Dimension dimPantalla = Toolkit.getDefaultToolkit().getScreenSize();
int nwidth,nheight;
if(wRel){
nwidth=(int)(width*(dimPantalla.width));
}else{
nwidth=width;
}
if(hRel){
nheight=(int)(height*(dimPantalla.height));
}else{
nheight=height;
}
resizeVainillaImg(nwidth,nheight);
}
public void resizeVainillaImg(int newWidth,int newHeight){
Image img = this.icimg.getImage();
BufferedImage bi = new BufferedImage(newWidth,newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, newWidth, newHeight,null);
g.dispose();
this.icimg = new ImageIcon(bi);
this.imagen.setIcon(this.icimg);
}
Although I didn't understand the setDimensions(), but I think you are trying to fit your image into screen width and height.
By multiplying int values of width and height in setDimensions(), you will simply be able to multiply small int numbers. For bigger numbers you will run out of memory because of huge image size (widthscreenwidth , heightscreenheight).
Lets assume you want to resize your image to percent of your screen, or use the default height and with of the image. Using the code below, pass negative number (-1 for example) to ignore the screen size, and 0> number to resize it to percent of screen.
I hope this help. However, it you have some other think in your mind, just remember to use float because of int * int multiplications :)
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JLabel;
/**
*
* #author Pasban
*/
public class VainillaImage {
private ImageIcon icimg;
private JLabel imagen;
public static void main(String args[]) {
JDialog d = new JDialog();
VainillaImage v = new VainillaImage("92-1024x576.jpg");
d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
d.getContentPane().add(v.imagen);
v.setDimensions(-1, 1);
d.pack();
d.setLocationRelativeTo(null);
d.setVisible(true);
}
public void setDimensions(double width, double height) {
Dimension dimPantalla = Toolkit.getDefaultToolkit().getScreenSize();
int nwidth, nheight;
nwidth = (int) (width * (dimPantalla.width));
nheight = (int) (height * (dimPantalla.height));
resizeVainillaImg(nwidth, nheight);
}
public void resizeVainillaImg(int newWidth, int newHeight) {
Image img = this.icimg.getImage();
newWidth = Math.max(newWidth, img.getHeight(null));
newWidth = Math.max(newHeight, img.getHeight(null));
BufferedImage bi = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, newWidth, newHeight, null);
g.dispose();
this.icimg = new ImageIcon(bi);
this.imagen.setIcon(this.icimg);
}
public VainillaImage(String url) {
this.icimg = new ImageIcon(url);
this.imagen = new JLabel(this.icimg);
this.imagen.setVisible(true);
}
}
If you are trying to dynamically resize an Icon based on the space available to the label then check out Darryl's Stretch Icon.
I'm using Java3D to visualize a room with some primitives in it. I have an image background that I tile so that it fills the entire frame using background.setImageScaleMode(Background.SCALE_REPEAT);. Now I would like to add another semitransparent background on top of this background, and I would like to stretch it to cover the screen using SCALE_FIT_ALL. This will create an image effect that I cannot otherwise achieve. However, when I try to do this Java 3D complains that Group.addChild: child already has a parent.
Other ways of doing the same thing without using backgrounds (e.g. draw it on a 2D primitive) would be a interest too.
So my question is how can I achieve what I want with Java3D?
MWE: Image are available here. I want to draw bg-stars.png with Background.SCALE_REPEAT and then on top of that bg-glow.png with Background.SCALE_FIT_ALL.
Probably not what you actually want to achieve, but too long for a comment:
I did a test of adding multiple Backgrounds, and it "worked" basically (that is: it did not cause an error message). But the documentation of Background says
If multiple Background nodes are active, the Background node that is "closest" to the eye will be used.
Thus, I assume that it is not possible at all to display multiple backgrounds simulataneously at all.
Depending on what you want to achieve, there are probably several possibilities. The following it one approach that might be "close" to what you want. But I am not familiar with Backgrounds in Java3D, and assume that there are more elegant, efficient, flexible (or simply: better) approaches (like creating a huge, semi-transparent quad with the overlay texture or whatever...)
However, the idea here was to create the background as a single image. Composing BufferedImages is rather easy and offers a lot of possibilities. So I'm taking the bg-stars.png image and create a "tiled" version of this image (large enough to fill a certain area - in practice, this could simply be made as large as the maximum screen size). Then I'm composing this with the "overlay" image, bg-glow.png, by just painting it over the tiled image.
The resulting image can then be used to create the Background.
At the first glance, the result may look like what you want to achieve, but of course, there may be some caveats. E.g. one has to think about how this could be implemented to adapt to changes of the window size. (Listening for this with a ComponentListener and updating the image would be easy, but ... well).
And again: There certainly are better solutions. But maybe this can at least serve as a workaround until you find the better solution.
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.image.TextureLoader;
import com.sun.j3d.utils.universe.SimpleUniverse;
public class SimpleBackgroundTest extends Applet
{
private static final int WIDTH = 1200;
private static final int HEIGHT = 1200;
public static void main(String[] args) throws IOException
{
System.setProperty("sun.awt.noerasebackground", "true");
Frame frame = new MainFrame(new SimpleBackgroundTest(), WIDTH, HEIGHT);
}
public SimpleBackgroundTest()
{
setLayout(new BorderLayout());
Canvas3D c = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
add("Center", c);
BranchGroup group = new BranchGroup();
group.addChild(createSomeCube());
BufferedImage stars = null;
BufferedImage glow = null;
try
{
stars = ImageIO.read(new File("bg-stars.png"));
glow = ImageIO.read(new File("bg-glow.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
BufferedImage tiled = createTiled(stars, WIDTH, HEIGHT);
BufferedImage overlay = createOverlay(tiled, glow);
Background background = createBackground(overlay);
group.addChild(background);
SimpleUniverse universe = new SimpleUniverse(c);
universe.addBranchGraph(group);
universe.getViewingPlatform().setNominalViewingTransform();
}
private static BufferedImage createTiled(
BufferedImage image, int targetSizeX, int targetSizeY)
{
BufferedImage result = new BufferedImage(
targetSizeX, targetSizeY,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = result.createGraphics();
for (int x = 0; x < targetSizeX; x += image.getWidth())
{
for (int y = 0; y < targetSizeY; y += image.getHeight())
{
g.drawImage(image, x, y, null);
}
}
g.dispose();
return result;
}
private static BufferedImage createOverlay(
BufferedImage image, BufferedImage overlay)
{
BufferedImage result = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = result.createGraphics();
g.drawImage(image, 0, 0, null);
g.drawImage(overlay, 0, 0, image.getWidth(), image.getHeight(), null);
g.dispose();
return result;
}
private static Background createBackground(BufferedImage image)
{
TextureLoader textureLoader = new TextureLoader(image);
ImageComponent2D imageComponent = textureLoader.getImage();
Background background = new Background();
background.setImage(imageComponent);
background.setImageScaleMode(Background.SCALE_FIT_ALL);
background.setCapability(Background.ALLOW_IMAGE_WRITE);
background.setApplicationBounds(new BoundingSphere());
return background;
}
private TransformGroup createSomeCube()
{
ColorCube cube = new ColorCube(0.5f);
Transform3D t = new Transform3D();
t.rotY(0.2);
t.setScale(0.1);
TransformGroup tg = new TransformGroup();
tg.setTransform(t);
tg.removeAllChildren();
tg.addChild(cube);
return tg;
}
}
I would like to display a DICOM image in my java program. I am using pixelmed. However, I found that i cant correctly display the correct contrast. The contrast is too low.
Here is my code:
(SourceImage is a class provided by PixelMed, chosenImageFile.getPath() is just the path of the DICOM File.)
SourceImage dimg = new SourceImage(chosenImageFile.getPath());
BufferedImage image = dimg.getBufferedImage();
BufferedImage source = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = source.createGraphics();
g2d.drawImage(image, 0, 0, null);
dicomImgDisplayer1.setImage(source);
dicomImgDisplayer1 is an class extend JPanel. setImage() of this JPanel class will call the setImage() of an JFrame class.
The JFrame class's setImage() code:
public void setImage(BufferedImage image) {
this.image = image;
setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
repaint();
revalidate();
}
public void paint(Graphics graphics) {
Graphics2D g2d = (Graphics2D) graphics;
g2d.drawImage(image, null, 0, 0);
}
Is that something wrong with the color model? Please help. Thanks.
Does your image have a prescribed window width / window center? Be sure you set that (or allow the user to adjust it). See SingleImagePanel - there are some static methods to apply windowing to your buffered image.
So I am attempting to create an application that can black-out sections of a survey that contains sensitive information. However I've run into a bit of a problem.
What I want to do is draw filled black rectangles over a BufferedImage given x, y, width, and height of desired region to black out, then write that new image back to my filesystem. Here's my code.
File imageFile = new File("images/template.jpg");
BufferedImage img = ImageIO.read(imageFile);
Graphics2D graph = img.createGraphics();
graph.setColor(Color.BLACK);
graph.fill(new Rectangle(x, y, width, height));
graph.dispose();
ImageIO.write(img, "jpg", new File("images/template.jpg"));
For whatever reason the image in the resource doesn't change after this code segment. Any ideas on what I'm doing wrong?
I created a runnable example of your code, and it worked fine for me. I ran this code using Java 8.
Here's the altered image. I drew the black square on an image I had.
And here's the code I ran. I read the original image directly from my file system.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageProcessing implements Runnable {
public static void main(String[] args) {
new ImageProcessing().run();
}
#Override
public void run() {
File imageFile = new File("C:\\Users\\Owner\\Pictures\\Saved Pictures\\Analog Clock Calendar.jpg");
BufferedImage img;
try {
img = ImageIO.read(imageFile);
} catch (IOException e1) {
e1.printStackTrace();
return;
}
Graphics2D graph = img.createGraphics();
graph.setColor(Color.BLACK);
graph.fill(new Rectangle(100, 100, 100, 100));
graph.dispose();
try {
ImageIO.write(img, "jpg",
new File("altered.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
My conclusion is that you either didn't read the image correctly, your x, y, width, and/or height were outside the limits of the image, or something else that I'm missing.
I know is an old question, but maybe it can be useful to someone,
I think you shoud use this
graph.drawImage(x,y,width,height); //First you draw the image
graph.setColor(Color.black); //Then set the color to black
graph.fillRect(img.getX(), img.getY(), img.getWidth(), img.getHeight());// Finally draw a black rectangle on it
By the way is hard to find a solution without a little more code.
Hope it will be usefull.
Very late to this answer but you are saving the image and not the graph you are creating. I think it must be a BufferedImage again to save
You have just to replace this line:
Graphics2D graph = img.createGraphics();
with this:
Graphics2D graph = img.getGraphics();