Cut out image in shape of text - java

I need to cut out an image in the shape of the text in another image. I think it's best shown in images.
This is a photo of a cat:
and this is the text I wish to cut out:
The resulting image would be this:
The text image will always be black with a transparent background, and the resulting cut-out should too have a transparent background. Both input images will also be the same size.

import java.awt.*;
import java.awt.font.*;
import java.awt.image.BufferedImage;
import java.awt.geom.Rectangle2D;
import javax.imageio.ImageIO;
import java.net.URL;
import java.io.File;
class PictureText {
public static void main(String[] args) throws Exception {
URL url = new URL("http://i.stack.imgur.com/Nqf3H.jpg");
BufferedImage originalImage = ImageIO.read(url);
final BufferedImage textImage = new BufferedImage(
originalImage.getWidth(),
originalImage.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = textImage.createGraphics();
FontRenderContext frc = g.getFontRenderContext();
Font font = new Font(Font.SANS_SERIF, Font.BOLD, 250);
GlyphVector gv = font.createGlyphVector(frc, "Cat");
Rectangle2D box = gv.getVisualBounds();
int xOff = 25+(int)-box.getX();
int yOff = 80+(int)-box.getY();
Shape shape = gv.getOutline(xOff,yOff);
g.setClip(shape);
g.drawImage(originalImage,0,0,null);
g.setClip(null);
g.setStroke(new BasicStroke(2f));
g.setColor(Color.BLACK);
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.draw(shape);
g.dispose();
File file = new File("cat-text.png");
ImageIO.write(textImage,"png",file);
Desktop.getDesktop().open(file);
}
}

Create a new BufferedImage and iterate over all the pixels of word cat and if they are black, copy the cat-image pixels to the new image.
Here is some code: (Final working code, supports anti-alias)
public static BufferedImage textEffect(BufferedImage image, BufferedImage text) {
if (image.getWidth() != text.getWidth() ||
image.getHeight() != text.getHeight())
{
throw new IllegalArgumentException("Dimensions are not the same!");
}
BufferedImage img = new BufferedImage(image.getWidth(),
image.getHeight(),
BufferedImage.TYPE_INT_ARGB_PRE);
for (int y = 0; y < image.getHeight(); ++y) {
for (int x = 0; x < image.getWidth(); ++x) {
int textPixel = text.getRGB(x, y);
int textAlpha = (textPixel & 0xFF000000);
int sourceRGB = image.getRGB(x, y);
int newAlpha = (int) (((textAlpha >> 24) * (sourceRGB >> 24)) / 255d);
int imgPixel = (newAlpha << 24) | (sourceRGB & 0x00FFFFFF);
int rgb = imgPixel | textAlpha;
img.setRGB(x, y, rgb);
}
}
return img;
}

Use GlyphVector. Use Font class
public GlyphVector layoutGlyphVector(FontRenderContext frc,
char[] text,
int start,
int limit,
int flags) {
You can get outline Shape from glyph vector by public abstract Shape getOutline()
Assign the outline Shape as a clip to your Graphics instance.
Draw the image on the graphics.
Only clipped shape will be filled.

No java here, but the needed image operations are easy to understand. In Mathematica:

You can do it in Java with just a few lines of source code, using Marvin Framework
source code:
public class CutAndFill {
public static void main(String[] args) {
// 1. Load images
MarvinImage catImage = MarvinImageIO.loadImage("./res/catImage.jpg");
MarvinImage catText = MarvinImageIO.loadImage("./res/catText.png");
// 2. Load plug-in, set parameters and process de image
MarvinImagePlugin combine = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.combine.combineByMask");
combine.setAttribute("combinationImage", catImage);
combine.setAttribute("colorMask", Color.black);
combine.process(catText.clone(), catText);
// 3. Save the output image.
MarvinImageIO.saveImage(catText, "./res/catOut.jpg");
}
}

First, make the black portion of the "Cat" image transparent. See here for help with this. Then, composite that image over the picture of your favorite cat (mine is Sheeba).
The nice thing about this is you can make the transparent text image once, save it, and then apply it to all of Sheeba's family and friends!

Related

Template Matching Java without opencv or 3rd party

I am trying to do template matching in java:
This is the code:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.awt.image.DataBufferByte;
public class pro {
public static void main(String[] args) {
try {
// RGB pixel values
byte[] pixels;
File inp=new File("TenCardG.jpg");
BufferedImage image = ImageIO.read(inp);
int width = image.getWidth();
int height = image.getHeight();
// System.out.println("Type: "+image.getColorModel());
pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.out.println("Dimension of image" + width + " "+height+" "+ " pixels length "+ pixels.length);
//rgb2gray in a 2D array grayImage
int pr;// red
int pg;// green
int pb;// blue
short [][] grayImage =new short [height][width];
int cord;
for (int i=0; i<height;i++)
for(int j=0;j<width;j++)
{
cord= 3*(i*width+j);
pr= ((short) pixels[cord] & 0xff); // red
pg= (((short) pixels[cord+1] & 0xff));// green
pb= (((short) pixels[cord+2] & 0xff));// blue
grayImage[i][j]=(short)Math.round(0.299 *pr + 0.587 * pg + 0.114 * pb);
}
Image scaledImage = image.getScaledInstance(-1,-1, 0);
ImageIO.write(
add_Rectangle(scaledImage),
"jpg",
new File("TenCardG2.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Done, check the generated TenCardG2 image at its left top corner");
}
// Add a rectangle of side size 50, 70 at coordinate 0.0 in image img
public static BufferedImage add_Rectangle(Image img) {
if (img instanceof BufferedImage) {
return (BufferedImage) img;
}
// Create a buffered image with transparency
BufferedImage bi = new BufferedImage(
img.getWidth(null), img.getHeight(null),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2D = bi.createGraphics();
g2D.drawImage(img, 0, 0, null);
g2D.setColor(Color.RED);
g2D.drawRect(0, 0, 50, 70);
g2D.dispose();
return bi;
}
}
This is the source image:10 of hearts
This is the template image: Picture of heart
This a matlab code i guess which we change it to java and then implement into that code. I guess that matlab code this it compares bit by bit like and image can be compressed. if so, it will not match. its static processing. we need dynamic one. I don't know where to implement that one
When i run my code which i provide up i get this output which i get
But i should this final output
Can please try to help me

Adding text to an image and make it fit into a rectangular region in Java

I am trying to add some text to an image in Java with the following code:
public static void main(String[] args) throws IOException {
BufferedImage image = ImageIO.read(new File("img.png"));
Graphics g = image.getGraphics();
Rectangle rectangle = new Rectangle(image.getWidth(), image.getHeight());
g.setFont(g.getFont().deriveFont(30f));
drawCenteredString(g, "TexvzgdsfadvcfkgsdASKJDFHJGgkdgfsakagjASGHDJStTexvzgdsfadvcfkgsdASKJDFHJGgkdgfsakagjASGHDJSt", rectangle, g.getFont());
g.dispose();
ImageIO.write(image, "png", new File("out.png"));
}
public static void drawCenteredString(Graphics g, String text, Rectangle rect, Font font) {
FontMetrics metrics = g.getFontMetrics(font);
int x = rect.x + (rect.width - metrics.stringWidth(text)) / 2;
int y = rect.y + ((rect.height - metrics.getHeight()) / 2) + metrics.getAscent();
g.setFont(font);
g.drawString(text, x, y);
}
But I have a problem: I would need to be able to scale the font size or send words to a new line so that the whole string fits in a rectangular region at the center of the image with a maximum size of x,y.
How can i do it?
To wrap the text, create TextLayout objects from a LineBreakMeasurer, and use TextLayout.draw instead of drawing with Graphics.drawString.
First, you need to create an AttributedCharacterIterator. You can do that by creating an AttributedString from your text:
AttributedString attrStr = new AttributedString(text);
AttributedCharacterIterator iter = attrStr.getIterator();
Now you can create a LineBreakMeasurer:
Graphics2D g2 = (Graphics2D) g;
LineBreakMeasurer measurer = new LineBreakMeasurer(iter,
g2.getFontRenderContext());
You then obtain the lines as TextLayouts, one at a time, from the LineBreakMeasurer:
List<TextLayout> lines = new ArrayList<>();
while (measurer.getPosition() < text.length()) {
lines.add(measurer.nextLayout(rect.width));
}
Once you have them, you can figure out the total height:
float textHeight = 0;
for (TextLayout line : lines) {
textHeight += line.getAscent() + line.getDescent() + line.getLeading();
}
Finally, you can draw the lines:
float y = (rect.height - textHeight) / 2;
for (TextLayout line : lines) {
Rectangle2D bounds = line.getBounds();
float x = (rect.width - (float) bounds.getWidth()) / 2;
line.draw(g2, x, y + line.getAscent());
y += line.getAscent() + line.getDescent() + line.getLeading();
}
I used an image I found on the web. Basically, you try with a large font size and reduce the font size until your text fits on the image.
Here's the image after I added the text.
I started with a font size of 96 and worked my way down to 46, which fit in the image.
Here's the complete runnable code.
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
public class AddTextToImage {
public static void main(String[] args) throws IOException {
URL url = new URL("https://clipartmag.com/images/car-cartoon-png-18.png");
BufferedImage image = ImageIO.read(url);
Graphics g = image.getGraphics();
Rectangle rectangle = new Rectangle(image.getWidth(), image.getHeight());
String text = "TexvzgdsfadvcfkgsdASKJDFHJGgkdgfsakagjASGHDJSt"
+ "TexvzgdsfadvcfkgsdASKJDFHJGgkdgfsakagjASGHDJSt";
int fontSize = 98;
FontMetrics metrics;
do {
fontSize -= 2;
g.setFont(g.getFont().deriveFont((float) fontSize));
metrics = g.getFontMetrics(g.getFont());
} while (metrics.stringWidth(text) > rectangle.width);
System.out.println("Font Size: " + fontSize);
drawCenteredString(g, text, rectangle, g.getFont());
g.dispose();
ImageIO.write(image, "png", new File("output.png"));
}
public static void drawCenteredString(Graphics g, String text, Rectangle rect, Font font) {
FontMetrics metrics = g.getFontMetrics(font);
int x = rect.x + (rect.width - metrics.stringWidth(text)) / 2;
int y = rect.y + ((rect.height - metrics.getHeight()) / 2) + metrics.getAscent();
g.setFont(font);
g.drawString(text, x, y);
}
}

Java recoloring BufferedImage not working with an image of a larger height

I have a program that is supposed to take the RGB values of an image and then multiply them by some constants, and then draw the new image on a JPanel. The problem is that if my image is over a certain height, specifically over 187 pixels, the new colored image is different than an image with a height of less than 187px.
The JPanel shows this: example.
Notice how the longer recolored image is different than the shorter one. I'm sure that the shorter image's colors are correct, and I have no idea how it's getting messed up.
public class RecolorImage extends JPanel {
public static int scale = 3;
public static BufferedImage walk, walkRecolored;
public static BufferedImage shortWalk, shortWalkRecolored;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(200*scale, 400*scale);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RecolorImage());
walk = ImageLoader.loadImage("/playerWalk.png");
walkRecolored = recolor(walk);
shortWalk = ImageLoader.loadImage("/playerWalkShort.png");
shortWalkRecolored = recolor(shortWalk);
frame.setVisible(true);
}
#Override
public void paint(Graphics graphics) {
Graphics2D g = (Graphics2D) graphics;
g.scale(scale, scale);
g.drawImage(walk, 10, 10, null);
g.drawImage(walkRecolored, 40, 10, null);
g.drawImage(shortWalk, 70, 10, null);
g.drawImage(shortWalkRecolored, 100, 10, null);
}
The recolor method:
public static BufferedImage recolor(BufferedImage image) {
BufferedImage outputImage = deepCopy(image);
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int rgb = image.getRGB(x, y);
Color c = new Color(rgb);
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
r *= 0.791;
g *= 0.590;
b *= 0.513;
int newRGB = (rgb & 0xff000000) | (r << 16) | (g << 8) | b;
outputImage.setRGB(x, y, newRGB);
}
}
return outputImage;
}
How I load the images and make deep copies:
public static BufferedImage loadImage(String path) {
try {
return ImageIO.read(ImageLoader.class.getResource(path));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static BufferedImage deepCopy(BufferedImage image) {
ColorModel colorModel = image.getColorModel();
boolean isAlphaPremultiplied = colorModel.isAlphaPremultiplied();
WritableRaster raster = image.copyData(null);
return new BufferedImage(colorModel, raster, isAlphaPremultiplied, null);
}
My original images: the tall image and short image. Thanks for any help!
Your source images have different color models:
the short image uses 4 bytes per pixel (RGB and alpha)
the tall image uses 1 byte per pixel (index into a palette of 256 colors)
Your recolored images use the same color model as the source images (thanks to the deepCopy method), therefore the recolored image for the tall image also uses the same color palette as the source image, meaning that it cannot contain all the colors you want.
Since your recoloring code overwrites each pixel of the output image anyway the deep copy operation is unnecessary. Instead you would better create a full color image as target image like this:
public static BufferedImage recolor(BufferedImage image) {
BufferedImage outputImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
//... code as before
}

Read in Bufferedimage pixel values then manipulate each one and write to file

I am currently trying to read in an image pixel by pixel and change each colored pixel to the rgb value of (100,100,100). For whatever reason when I check the values of each pixel one the image is saved it has all the colored pixels as (46,46,46) instead.
Here is the original image
After running my program this is the image it gives to me
Here is the code
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Cmaps {
public static void main(String[] args){
File originalImage = new File("C:\\Users\\Me\\Desktop\\0005.bmp");
BufferedImage img = null;
try{
img = ImageIO.read(originalImage);
for(int i = 0; i < img.getHeight(); i++){
for(int j = 0; j < img.getWidth(); j++){
//get the rgb color of the image and store it
Color c = new Color(img.getRGB(i, j));
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
//if the pixel is white then leave it alone
if((r == 255) && (g == 255) && (b == 255)){
img.setRGB(i, j, c.getRGB());
continue;
}
//set the colored pixel to 100,100,100
r = 100;// red component 0...255
g = 100;// green component 0...255
b = 100;// blue component 0...255
int col = (r << 16) | (g << 8) | b;
img.setRGB(i, j, col);
}
}
File f = new File("C:\\Users\\Me\\Desktop\\2\\1.png");
try {
ImageIO.write(img, "PNG", f);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e){
e.printStackTrace();
}
}
}
I have no clue why it doesn't set the pixels to the expected rgb value. I eventually want to be able to basically increment the rgb color as I move down rows and columns in the x and y so what the final image will look like is it will start off dark in the top left corner and then have a fade out effect as you get from that side to the bottom right corner.
Okay, based on the comments:
If the BufferedImage has an IndexColorModel (palette based color model), using setRGB to set a pixel to an arbitrary RGB value will not work. Instead, the color will be looked up, and the pixel will get the color that is considered the closest match in the palette.
Formats like BMP, GIF and PNG may all use IndexColorModel when read using ImageIO.
To convert the image to "true color" (either DirectColorModel or ComponentColorModel in Java will do), you can use:
BufferedImage img; // your original palette image
int w = img.getWidth();
int h = img.getHeight();
BufferedImage trueColor = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = trueColor.createGraphics();
try {
g.drawImage(img, 0, 0, null);
}
finally {
g.dispose();
}
img = trueColor;
After this, getRGB(x, y) should return what you specify, using setRGB(x, y, argb).

Get color of each pixel of an image using BufferedImages

I am trying to get every single color of every single pixel of an image.
My idea was following:
int[] pixels;
BufferedImage image;
image = ImageIO.read(this.getClass.getResources("image.png");
int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
Is that right? I can't even check what the "pixels" array contains, because i get following error:
java.awt.image.DataBufferByte cannot be cast to java.awt.image.DataBufferInt
I just would like to receive the color of every pixel in an array, how do i achieve that?
import java.io.*;
import java.awt.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
public class GetPixelColor {
public static void main(String args[]) throws IOException {
File file = new File("your_file.jpg");
BufferedImage image = ImageIO.read(file);
// Getting pixel color by position x and y
int clr = image.getRGB(x, y);
int red = (clr & 0x00ff0000) >> 16;
int green = (clr & 0x0000ff00) >> 8;
int blue = clr & 0x000000ff;
System.out.println("Red Color value = " + red);
System.out.println("Green Color value = " + green);
System.out.println("Blue Color value = " + blue);
}
}
of course you have to add a for loop for all pixels
The problem (also with the answer that was linked from the first answer) is that you hardly ever know what exact type your buffered image will be after reading it with ImageIO. It could contain a DataBufferByte or a DataBufferInt. You may deduce it in some cases via BufferedImage#getType(), but in the worst case, it has type TYPE_CUSTOM, and then you can only fall back to some instanceof tests.
However, you can convert your image into a BufferedImage that is guaranteed to have a DataBufferInt with ARGB values - namely with something like
public static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
Otherwise, you can call image.getRGB(x,y), which may perform the required conversions on the fly.
BTW: Note that obtaining the data buffer of a BufferedImage may degrade painting performance, because the image can no longer be "managed" and kept in VRAM internally.
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
BufferedImage bufferedImage = ImageIO.read(new File("norris.jpg"));
int height = bufferedImage.getHeight(), width = bufferedImage.getWidth();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int RGBA = bufferedImage.getRGB(x, y);
int alpha = (RGBA >> 24) & 255;
int red = (RGBA >> 16) & 255;
int green = (RGBA >> 8) & 255;
int blue = RGBA & 255;
}
}
}
}
Assume the buffered image represents an image with 8-bit RGBA color components packed into integer pixels, I search for "RGBA color space" on wikipedia and found following:
In the byte-order scheme, "RGBA" is understood to mean a byte R,
followed by a byte G, followed by a byte B, and followed by a byte A.
This scheme is commonly used for describing file formats or network
protocols, which are both byte-oriented.
With simple Bitwise and Bitshift you can get the value of each color and the alpha value of the pixel.
Very interesting is also the other order scheme of RGBA:
In the word-order scheme, "RGBA" is understood to represent a complete
32-bit word, where R is more significant than G, which is more
significant than B, which is more significant than A. This scheme can
be used to describe the memory layout on a particular system. Its
meaning varies depending on the endianness of the system.
byte[] pixels
not
int[] pixels
try this : Java - get pixel array from image
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageUtil {
public static Color[][] loadPixelsFromImage(File file) throws IOException {
BufferedImage image = ImageIO.read(file);
Color[][] colors = new Color[image.getWidth()][image.getHeight()];
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
colors[x][y] = new Color(image.getRGB(x, y));
}
}
return colors;
}
public static void main(String[] args) throws IOException {
Color[][] colors = loadPixelsFromImage(new File("image.png"));
System.out.println("Color[0][0] = " + colors[0][0]);
}
}
I know this has already been answered, but the answers given are a bit convoluted and could use improvement.
The simple idea is to just loop through every (x,y) pixel in the image, and get the color of that pixel.
BufferedImage image = MyImageLoader.getSomeImage();
for ( int x = 0; x < image.getWidth(); x++ ) {
for( int y = 0; y < image.getHeight(); y++ ) {
Color pixel = new Color( image.getRGB( x, y ) );
// Do something with pixel color here :)
}
}
You could then perhaps wrap this method in a class, and implement Java's Iterable API.
class IterableImage implements Iterable<Color> {
private BufferedImage image;
public IterableImage( BufferedImage image ) {
this.image = image;
}
#Override
public Iterator<Color> iterator() {
return new Itr();
}
private final class Itr implements Iterator<Color> {
private int x = 0, y = 0;
#Override
public boolean hasNext() {
return x < image.getWidth && y < image.getHeight();
}
#Override
public Color next() {
x += 1;
if ( x >= image.getWidth() ) {
x = 0;
y += 1;
}
return new Color( image.getRGB( x, y ) );
}
}
}
The usage of which might look something like the following
BufferedImage image = MyImageLoader.getSomeImage();
for ( Color color : new IterableImage( image ) ) {
// Do something with color here :)
}

Categories

Resources