I am trying to shrink an image to half its height and width. This is what I have so far. I have no clue where to go from there.
One way to do it is to simply replace a group of pixels from the original image with a single pixel in the new shrunken image which is the average color over the group in the original.
I can also create a new array whose height and width are half the height and width of the image passed in as an argument. Then, insert new pixels into the new image as I figure out what the color values should be.
public class ImageManipulation
{
public static void main(String[] args) throws FileNotFoundException
{
Pixel[][] image = readImage("griff.ppm");
flipVertical(image);
writeImage(image,"manipulatedImage.ppm");
}
public static void grayscale(Pixel[][] imageArr)
{
int height = imageArr.length;
int width = imageArr[0].length;
for(int row = 0; row < height; row++)
{
for(int col = 0; col < width; col++)
{
Pixel p = imageArr[row][col];
int grayValue = (p.getRed() + p.getBlue() + p.getGreen())/3;
p.setBlue(grayValue);
p.setGreen(grayValue);
p.setRed(grayValue);
imageArr[row][col] = p;
}
}
}
public static void shrink (Pixel[][] imageArr)
{
int height = imageArr.length/2;
int width = imageArr[0].length/2;
No, you don't need to write all that code yourself :)
public BufferedImage shrink(File source, int w, int h) {
int dstWidth = w / 2;
int dstHeight = h / 2;
BufferedImage originalImage = ImageIO.read(source);
BufferedImage resizedImage = new BufferedImage(
dstWidth
, dstHeight
, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, dstWidth, dstHeight, null);
g.dispose();
return resizedImage;
}
Related
I have a Bufferedimage that is 1px high and eg wide. I need to create another Bufferedimage that will be in 1:1 resolution. I know what can be done in this case by calculating the square root of the width, but what if the result is not an integer? I have a method for creating a matrix (a list of each pixel in turn) from the width and height, so there will be no problems. At the end, if there are empty pixels, I can make them transparent, so not necessarily a completely filled square. I just need to get the dimensions of the square, having the width of the original photo, I will fill in the pixels myself.
my code:
public static BufferedImage encode(String str){
byte[] bytes = str.getBytes();
BufferedImage img = new BufferedImage(bytes.length, 1, BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < bytes.length; i++) {
img.setRGB(i, 0,encode(bytes[i]).getRGB() );
}
return img;
}
public static Color encode(byte byt){
return new Color(byt+128,byt+128,byt+128);
}
public static BufferedImage encode(String str){
byte[] bytes = str.getBytes();
int w = bytes.length;
int width = (int) Math.ceil(Math.sqrt(w));
BufferedImage img = new BufferedImage(width, width, BufferedImage.TYPE_INT_ARGB);
for (int index = 0; index < bytes.length; index++) {
img.setRGB(index%width, (int)Math.floor(index/(float)width),encode(bytes[index]).getRGB() );
}
return img;
}
code update. I just calculate the square root, and if the number is not an integer, then I round up to a larger one and as a result I get the height of the image, because the image has a 1:1 format, we immediately got the width. Then I just fill in the formula:
x = byteIndex % imageWidth
y = floor(byteIndex / imageHeight)
I've seen many questions about this, but all of them are C#. None of them are Java, and I couldn't find a proper library for this.
What library can do this for me programmatically by giving it a string/hash? This algorithm is actually implemented on StackExchange.
You can look at this link. There is a code that you could use to generate your identicons http://www.davidhampgonsalves.com/Identicons
The code for Java is the following one:
public static BufferedImage generateIdenticons(String text, int image_width, int image_height){
int width = 5, height = 5;
byte[] hash = text.getBytes();
BufferedImage identicon = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = identicon.getRaster();
int [] background = new int [] {255,255,255, 0};
int [] foreground = new int [] {hash[0] & 255, hash[1] & 255, hash[2] & 255, 255};
for(int x=0 ; x < width ; x++) {
//Enforce horizontal symmetry
int i = x < 3 ? x : 4 - x;
for(int y=0 ; y < height; y++) {
int [] pixelColor;
//toggle pixels based on bit being on/off
if((hash[i] >> y & 1) == 1)
pixelColor = foreground;
else
pixelColor = background;
raster.setPixel(x, y, pixelColor);
}
}
BufferedImage finalImage = new BufferedImage(image_width, image_height, BufferedImage.TYPE_INT_ARGB);
//Scale image to the size you want
AffineTransform at = new AffineTransform();
at.scale(image_width / width, image_height / height);
AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
finalImage = op.filter(identicon, finalImage);
return finalImage;
}
I solved the problem.
I used Gravatar. I first got the link of the image and stored it as a String like this:
String identiconURL = "http://www.gravatar.com/avatar/" + userID + "?s=55&d=identicon&r=PG";
Then, I used Glide:
Glide.with(ProfilePictureChooserActivity.this)
.load(identiconURL)
.centerCrop()
.into(imageView);
I am new to programming and I'm currently working on a program that rotates an image to the right and upside down. I was able to get the upside down method working but not the rotate to the right (90 degrees clockwise). It keeps giving me an out of bounds error, and I'm not sure why as I have looked at other examples. Any help would be appreciated.
Here's is the method that I'm working on:
public Image rotateRight()
{
Image right = new Image (this);
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int width = right.img.getWidth();
int height = right.img.getHeight();
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
{
this.img.setRGB(height-j-1,i,right.img.getRGB(i,j));
}
return right;
}
Here's the rest of the code:
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
public class Image {
private BufferedImage img = null;
int width;
int height;
private Image()
{
}
public Image (int w, int h)
{
img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB );
width = w;
height = h;
}
public Image (Image anotherImg)
{
width = anotherImg.img.getWidth();
height = anotherImg.img.getHeight();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB );
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
{
this.img.setRGB(j,i,anotherImg.img.getRGB(j,i)) ;
}
}
public String toString()
{
return "Width of Image:" +width+"\nHeight of Image:"+height;
}
public Image (String filename)
{
try
{
img = ImageIO.read(new File(filename));
width = img.getWidth();
height = img.getHeight();
}
catch (IOException e)
{
System.out.println(e);
}
}
public void save(String filename, String extension)
{
try
{
File outputfile = new File(filename);
ImageIO.write(img, extension, outputfile);
}
catch (IOException e)
{
System.out.println(e);
}
}
public Image copy()
{
Image copiedImage = new Image(this);
return copiedImage;
}
Here's Main:
public static void main (String args[])
{
Image srcimg = new Image("apple.jpg");
System.out.println(srcimg);
Image copy = srcimg.copy();
copy.save("apple-copy.jpg", "jpg");
Image copy2 = srcimg.copy();
Image right = copy2.rotateRight();
right.save("apple-rotateRight.jpg", "jpg");
}
The reason you are getting an ArrayIndexOutOfBoundsException when rotating your image is as stated. Something is out of bounds. It could be either your i variable that has exceeded its bounds or your j variable that has exceeded its bounds and this is generally easy to test for by just adding a print statement within your for loop and checking which one of the two values is out of bounds. It is good practice to try to resolve these problems yourself as you will start learning what causes these and where the problem lies.
Anyways enough of my rambling. The problem that you seem to have is that you are trying to turn the image without changing the size of the image.
You are creating a new Image with the same width and height parameters as the original
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB );
However when you want to rotate an image by 90 degrees you actually want to flip the width and height parameters. If you think about it, it makes sense when you rotate an image by 90 degrees the width will become the height and the height will become the width.
So your problem is here:
this.img.setRGB(height-j-1,i,right.img.getRGB(i,j));
In your case the bounds for the x parameter in the setRGB function is from 0 to the WIDTH of your image and the y parameter is from 0 to the HEIGHT of your image. Therefore because your height variable is different from your width. If for example your WIDTH is 200 and your HEIGHT is 100. When you put this in to the function the greatest value for the x parameter will be:
'100 - 199 - 1 = -100' which is clearly out of bounds. However if we change your code to.
img = new BufferedImage(height, width, BufferedImage.TYPE_INT_RGB );
now when we do the same thing as before where we get the maximum possible value.
WIDTH = 100, HEIGHT = 200;
'200 - 99 - 1 = 100' which is inside the bounds
I wanna change different pixel to different color. Basically, change part of pixel to transparent.
for(int i = 0; i < image.getWidth();i++)
for(int j = 0; j < image.getHeight(); j ++)
{
image.setRGB(i,j , 0);
}
//I aslo change the third parameter 0 to another attribute. but it still does not work. it all show black. do you have some ideas?
yin.
thanks
class ImagePanel extends JPanel {
private BufferedImage image;
public ImagePanel(int width, int height, BufferedImage image) {
this.image = image;
image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
repaint();
}
/**
* Draws the image.
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < image.getWidth(); i++) {
for (int j = 0; j < image.getHeight(); j++) {
image.setRGB(i, j, 0);
}
}
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
}
The third parameter is ARGB value in 32 bits. This is laid out in bit form as:
AAAAAAAA|RRRRRRRR|GGGGGGGG|BBBBBBBBB
See the javadoc for BufferedImage.setRGB (assuming your using BufferedImage, your question doesn't actually say...)
Sets a pixel in this BufferedImage to the specified RGB value. The
pixel is assumed to be in the default RGB color model, TYPE_INT_ARGB,
and default sRGB color space. For images with an IndexColorModel, the
index with the nearest color is chosen
If you're using an image type that supports transparency it is important you set alpha 255 means fully opaque, 0 is fully transparent.
You can create such a value using bit shifting.
int alpha = 255;
int red = 0;
int green = 255;
int blue = 0;
int argb = alpha << 24 + red << 16 + green << 8 + blue
image.setRGB(i, j, argb);
Luckily there is a getRGB() method on java.awt.Color instances, so you could use
image.setRGB(i, j, Color.green.getRGB());
Here's a full working example, perhaps you can compare to your code:
public class StackOverflow27071351 {
private static class ImagePanel extends JPanel {
private BufferedImage image;
public ImagePanel(int width, int height, BufferedImage image) {
this.image = image;
image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < image.getWidth(); i++) {
for (int j = 0; j < image.getHeight(); j++) {
image.setRGB(i, j, new Color(255, 0, 0, 127).getRGB());
}
}
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
int width = 640;
int height = 480;
frame.setSize(width, height);
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(new ImagePanel(width, height, image));
frame.setVisible(true);
}
}
Well, 3rd parameter is the color in RGB, so it will be black if you set it to 0.
here is a sample code:
private int colorToRGB(int alpha, int red, int green, int blue) {
int newPixel = 0;
newPixel += alpha;
newPixel = newPixel << 8;
newPixel += red;
newPixel = newPixel << 8;
newPixel += green;
newPixel = newPixel << 8;
newPixel += blue;
return newPixel;
}
then
image.setRGB(i, j, colorToRGB(alpha, 0, 0, 0))
I use the following form:
int[] pixel = new int[4];
// the following four ints must range 0..255
pixel[0] = redValue;
pixel[1] = greenValue;
pixel[2] = bluleValue;
pixel[3] = alphaValue;
raster.setPixel(x, y, pixel);
To get a raster for a BufferedImage, I do this:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = image.getRaster();
I've done some performance testing, and have not found that stuffing all the bytes of color values into a single number to make much of a difference.
It is also good to know the technique where one can draw an opaque image (e.g., RGB rather than an ARGB) with an alpha value.
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) (yourAlpha)));
g2d.drawImage(...);
I have snippet of code that I am using for the purpose of resizing an image to a curtain size (I want to change the resolution to something like 200 dpi). Basically the reason I need it is because I want to display the image that the user have picked (somewhat large) and then if the user approves I want to display the same image in a different place but using a smaller resolution. Unfortunately, if I give it a large image nothing appears on the screen. Also, if I change
imageLabel.setIcon(newIcon);
to
imageLabel.setIcon(icon);
I get the image to display but not in the correct resolution that's how I know that I have a problem inside this snipper of code and not somewhere else.
Image img = icon.getImage();
BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
BufferedImage bi = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
boolean myBool = g.drawImage(img, 0, 0, 100, 100, null);
System.out.println(myBool);
ImageIcon newIcon = new ImageIcon(bi);
imageLabel.setIcon(newIcon);
submitText.setText(currentImagePath);
imageThirdPanel.add(imageLabel);
You don't really have to care about the details of scaling images. The Image class has already a method getScaledInstance(int width, int height, int hints) designed for this purpose.
Java documentation says:
Creates a scaled version of this image. A new Image object is returned
which will render the image at the specified width and height by
default. The new Image object may be loaded asynchronously even if the
original source image has already been loaded completely. If either
the width or height is a negative number then a value is substituted
to maintain the aspect ratio of the original image dimensions.
And you can use it like this:
// Scale Down the original image fast
Image scaledImage = imageToScale.getScaledInstance(newWidth, newHighth, Image.SCALE_FAST);
// Repaint this component
repaint();
Check this for a complete example.
Here is my solution:
private BufferedImage resizeImage(BufferedImage originalImage, int width, int height, int type) throws IOException {
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
Try this CODE to resize image :
public static Image scaleImage(Image original, int newWidth, int newHeight) {
//do nothing if new and old resolutions are same
if (original.getWidth() == newWidth && original.getHeight() == newHeight) {
return original;
}
int[] rawInput = new int[original.getHeight() * original.getWidth()];
original.getRGB(rawInput, 0, original.getWidth(), 0, 0, original.getWidth(), original.getHeight());
int[] rawOutput = new int[newWidth * newHeight];
// YD compensates for the x loop by subtracting the width back out
int YD = (original.getHeight() / newHeight) * original.getWidth() - original.getWidth();
int YR = original.getHeight() % newHeight;
int XD = original.getWidth() / newWidth;
int XR = original.getWidth() % newWidth;
int outOffset = 0;
int inOffset = 0;
for (int y = newHeight, YE = 0; y > 0; y--) {
for (int x = newWidth, XE = 0; x > 0; x--) {
rawOutput[outOffset++] = rawInput[inOffset];
inOffset += XD;
XE += XR;
if (XE >= newWidth) {
XE -= newWidth;
inOffset++;
}
}
inOffset += YD;
YE += YR;
if (YE >= newHeight) {
YE -= newHeight;
inOffset += original.getWidth();
}
}
return Image.createRGBImage(rawOutput, newWidth, newHeight, false);
}
Another example is given here :
2D-Graphics/LoadImageandscaleit.htm">http://www.java2s.com/Tutorial/Java/0261_2D-Graphics/LoadImageandscaleit.htm
http://www.java2s.com/Code/JavaAPI/java.awt/ImagegetScaledInstanceintwidthintheightinthints.htm