Cut out image in shape of text
Asked Answered
N

6

46

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:

Photo of a nice cat

and this is the text I wish to cut out:

Text to cut out of the cat photo

The resulting image would be this:

Resulting cut-out of the cat photo

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.

Nexus answered 9/6, 2011 at 15:10 Comment(4)
Whatever. Cat? Immediate +1!Rafaelof
You filled up the internal "a" hole. Was that intentional?Correggio
@belisarius Well spotted - no that was not intentional ;)Nexus
Wouldn't be better if you have an image and a text instead? ( just asking )Languishing
B
21

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;
}
Bouncy answered 9/6, 2011 at 15:17 Comment(4)
How would you iterate over all pixels of word cat? What if the word is dog? From OP - the text is always in black, so just replace all black pixels with corresponsing pixels from other image?Oops
@Lobo Yes, that is what he is suggesting.Nitriding
One tiny suggestion: instead of converting to double when calculating newAlpha, just move the division to the end after the multiplication.Bayle
@Mark: Thanks, it is indeed a bit neater.Bouncy
A
39

Cat text

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("https://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);
    }
}
Adobe answered 9/6, 2011 at 16:47 Comment(1)
JDK only solutionRenaterenato
B
21

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;
}
Bouncy answered 9/6, 2011 at 15:17 Comment(4)
How would you iterate over all pixels of word cat? What if the word is dog? From OP - the text is always in black, so just replace all black pixels with corresponsing pixels from other image?Oops
@Lobo Yes, that is what he is suggesting.Nitriding
One tiny suggestion: instead of converting to double when calculating newAlpha, just move the division to the end after the multiplication.Bayle
@Mark: Thanks, it is indeed a bit neater.Bouncy
F
15

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.

Fallfish answered 9/6, 2011 at 15:27 Comment(0)
C
8

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

enter image description here

Correggio answered 9/6, 2011 at 15:29 Comment(1)
probably the OP wants to create a method like this in first place.Languishing
P
3

You can do it in Java with just a few lines of source code, using Marvin Framework

enter image description here

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");
    }
}
Phelloderm answered 10/11, 2013 at 16:42 Comment(0)
G
-1

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!

Grass answered 9/6, 2011 at 15:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.