Creating/Cropping image base on number of pixels Java - java

How can i crop an image to a specified number of pixels or create image that the output will be base on number of pixel not rectangular shape.
By using the code below i can only get square or rectangle shape.
BufferedImage out = img.getSubimage(0, 0, 11, 11);
But it only crops it to rectangular shape
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class raNd{
public static void main(String args[])throws IOException{
//image dimension
int width = 10;
int height = 10;
//create buffered image object img
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
//file object
File f = null;
//create random image pixel by pixel
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int a = 255;//(int)(Math.random()*256); //alpha
int r = (int)(Math.random()*256); //red
int g = (int)(Math.random()*256); //green
int b = (int)(Math.random()*256); //blue
int p = (a<<24) | (r<<16) | (g<<8) | b; //pixel
img.setRGB(x, y, p);
}
}
//write image
try{
f = new File("/Users/kingamada/Documents/Java/Test6.png");
BufferedImage out = img.getSubimage(0, 0, 5, 2);
ImageIO.write(out, "png", f);
}catch(IOException e){
System.out.println("Error: " + e);
}
}//main() ends here
}//class ends here
Sample Picture
I want the last white pixels cropped out, so the picture will not be rectangle.

So assuming the number of pixels you need to keep is in variable int pixelsLimit;:
int pixels = 0;
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int p = 0;
if (pixels < pixelsLimit) {
int a = 255;//(int)(Math.random()*256); //alpha
int r = (int)(Math.random()*256); //red
int g = (int)(Math.random()*256); //green
int b = (int)(Math.random()*256); //blue
p = (a<<24) | (r<<16) | (g<<8) | b; //pixel
}
img.setRGB(x, y, p);
++pixels;
}
}

Java images are rectangular, but people have suggested you can set the pixels you don't want to be transparent.
Ellipse2D clip = new Ellipse2D.Double(0, 0, width, height);
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
if(!clip.contains(x,y)){
img.setRGB(x, y, 0);
}
}
}
This could directly be added to existing code to make your image an ellipse. Another way would be to use a clipping shape and a graphics object. I've replaced your complete write image block.
//write image
try{
f = new File("Test6.png");
Ellipse2D clip = new Ellipse2D.Double(0, 0, width, height);
BufferedImage clipped = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = clipped.getGraphics();
g.setClip(clip); //ellipse from above.
g.drawImage(img, 0, 0, null);
g.dispose();
ImageIO.write(clipped, "png", f);
}catch(IOException e){
System.out.println("Error: " + e);
}
This compiled for me and wrote a tiny circular image.

Related

Panning a BufferedImage

How can I delete say 50px of the leftmost vertical column of a BufferedImage, and copy that into a new BufferedImage the same size as the original BufferedImage?
class TestCopyImage {
var img: BufferedImage? = null
private val rnd = Random()
fun create(screenWidth: Int, screenHeight: Int) {
img = BufferedImage(screenWidth, screenHeight, BufferedImage.TYPE_INT_RGB)
//Grab the graphics object off the image
val graphics = img!!.createGraphics()
//val stroke: Stroke = BasicStroke(1f)
//graphics.setStroke(stroke);
// Fill the image buffer
for (i in 1..screenWidth) {
for (j in 1..screenHeight) {
val r: Int = rnd.nextInt(255)
val g: Int = rnd.nextInt(255)
val b: Int = rnd.nextInt(255)
val randomColor = Color(r, g, b)
graphics.paint = randomColor
graphics.fill(Rectangle(i , j , 1, 1))
}
}
// Get a subimage, deleting 50 pixels of the left-most vertical portion.
img = img!!.getSubimage(50, 0, screenWidth - 50 , screenHeight)
// TODO Now copy that into a new image, same size as the original buffer?
img = BufferedImage(screenWidth, screenHeight, BufferedImage.TYPE_INT_RGB)
}
}
Here's a Java version of what you can do:
int panDist = 50;
BufferedImage subImg = img.getSubimage(panDist, 0, img.getWidth() - panDist, img.getHeight());
BufferedImage newImg = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
for (int x = 0; x < subImg.getWidth(); ++x) {
for (int y = 0; y < subImg.getHeight(); ++y) {
newImg.setRGB(x, y, subImg.getRGB(x, y));
}
}
The subimage isn't really necessary though, you could skip that and just do this instead:
int panDist = 50;
BufferedImage newImg = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
for (int x = panDist; x < img.getWidth(); ++x) {
for (int y = 0; y < img.getHeight(); ++y) {
newImg.setRGB(x - panDist, y, img.getRGB(x, y));
}
}
You could also tweak that slightly to modify the image in-place instead.

Create different shaped pixel?

I was ready through Wikipedia about Pixel, I found out that a pixel can be rendered in different shapes, and not necessarily square shape.
How can I create image with different shaped pixels in Java?
Below is how I create an Image with Random pixels
/**
* File: RandomImage.java
*
* Description:
* Create a random color image.
*
* #author King Amada
* Date: 07-17-20148 tue
*/
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class RandomImage{
public static void main(String args[])throws IOException{
//image dimension
int width = 640;
int height = 320;
//create buffered image object img
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//file object
File f = null;
//create random image pixel by pixel
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int a = (int)(Math.random()*256); //alpha
int r = (int)(Math.random()*256); //red
int g = (int)(Math.random()*256); //green
int b = (int)(Math.random()*256); //blue
int p = (a<<24) | (r<<16) | (g<<8) | b; //pixel
img.setRGB(x, y, p);
}
}
//write image
try{
f = new File("D:\\Image\\Output.png");
ImageIO.write(img, "png", f);
}catch(IOException e){
System.out.println("Error: " + e);
}
}//main() ends here
}//class ends here

convert Random text to image with random noise in java

I am implementing captcha feature in our project. Its basically Tapestry framework application. I am generating random alfa-numeric string and convert it to image and display it in web page.
Now what i need is, i want to add random noise like dots lines etc to make image with text unclear. How to proceed please help.
keeping the code for reference .
-- This method gives text captcha.
`
public String generateCaptcha() {
Random random = new Random();
int min = 4; // Inclusive
int max = 9; // Exclusive
int length = random.nextInt(max-min) + min;
StringBuilder captchaStringBuffer = new StringBuilder();
for (int i = 0; i < length; i++) {
int captchaNumber = Math.abs(random.nextInt()) % 60;
int charNumber = 0;
if (captchaNumber < 26) {
charNumber = 65 + captchaNumber;
}
else if (captchaNumber < 52){
charNumber = 97 + (captchaNumber - 26);
}
else {
charNumber = 48 + (captchaNumber - 52);
}
captchaStringBuffer.append((char)charNumber);
}
return captchaStringBuffer.toString();
}
`
-- This method converts generated captcha to Image with out any noise.
`
public void textToImage(String displayCode){
String text = displayCode;
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = new Font("Arial", Font.PLAIN, 48);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int width = fm.stringWidth(text);
int height = fm.getHeight();
g2d.dispose();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_DISABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_DEFAULT);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, "png", baos);
byte[] res=baos.toByteArray();
setBinaryImage("data:image/png;base64,"+Base64.encode(res));
} catch (IOException e) {
}
}
`
I am newbie so please tell in clear what ever you say.
Thanks in Advance :-)
When trying to obstruct the text that is being displayed, you can use:
Dots/Circles, spread randomly over the image with varying size and color
Lines, coming from a random point on the edge of the image to another point on the edge of the image. These can also vary in color and thickness.
As far as i know, you can use g2d.drawLine(x1, y1, x2, y2) to draw a line. Since you want it to go from the edge to another point on the edge, you have to limit your random-point-generation. You can use this approach:
public Point pointOnEdge(int width, int height) {
int side = (int) (Math.random() * 3); //0=top, 1=bot, 2=left, 3=right
int x = 0;
int y = 0;
switch(side) {
case 0:
//when on top, y is at the top of the image (0) and x is something in [0, width]
y = 0;
x = (int) (Math.random() * width);
break;
case 1:
//when on bottom, y is at the bottom of the image (image height) and x is something in [0, width]
y = height;
x = (int) (Math.random() * width);
case 2:
//when on left, x is at the left side (0) of the image and y is something in [0, height]
y = (int) (Math.random() * height);
x = 0;
break;
case 3:
//when on left, x is at the left side (0) of the image and y is something in [0, height]
y = (int) (Math.random() * height);
x = width;
break;
}
return new Point(x, y);
}
If you create two Points like that, and connect them with a line, then you have a pretty simple way of obstructing your Image Partially, thus distorting it.
Now to the Circles:
public void drawCircles(Graphics2D g2d, int width, int height) {
//draw 10 of them
for(int i = 0; i < 10; i++) {
//select a random size
int x = 10 + (int) (Math.random() * 10);
//draw circle at random position with the created size
g2d.fillOval((int) (Math.random() * width), (int) (Math.random() * height), x, x);
}
}
And like that you are now able to distort your image to make it hard to read.
I hope you have enough common code understanding to know where to put these function calls. If not, I can add it if nescessary.
EDIT 1
If you want a dotted Background for your Captcha, you can use this code before rendering the String or anything else:
boolean r = false;
boolean g = false;
for(int y = 0; y < height; y++) {
r = !r;
g = r;
for(int x = 0; x < width; x++) {
g = !g;
if(g) {
g2d.setColor(Color.GRAY);
}else {
g2d.setColor(Color.WHITE);
}
g2d.drawLine(x, y, x, y);
}
}
EDIT 2
I would recommend, that you use a different font. Then you dont have to do any streching. Good fonts for that are e.g. Gigi. You could also select a font randomly by using GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames() which returns all Fonts that Java has.

Can't draw BufferedImage into another BufferedImage with scale

Please advise.
I'm trying to draw input BufferedImage into larger output BufferedImage (with scaling). Please, take a look at the following code:
public class Main {
public void print(BufferedImage img, int width, int height) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
System.out.print(img.getRGB(x, y) + " ");
}
System.out.println("");
}
}
public static void main(String[] args) {
Main app = new Main();
// create input image
int inputWidth = 2;
int inputHeight = 2;
BufferedImage inputImg = new BufferedImage(inputWidth, inputHeight, BufferedImage.TYPE_INT_ARGB);
// fill input image
for (int y = 0; y < inputHeight; y++) {
for (int x = 0; x < inputWidth; x++) {
inputImg.setRGB(x, y, y * inputWidth * (1 << 16) + x);
}
}
// print
app.print(inputImg, inputWidth, inputHeight);
// create output image
int outputWidth = 4;
int outputHeight = 4;
BufferedImage outputImg = new BufferedImage(outputWidth, outputHeight, BufferedImage.TYPE_INT_ARGB);
// draw inputImg into outputImg
Graphics2D g = outputImg.createGraphics();
g.drawImage(inputImg, 0, 0, outputImg.getWidth(), outputImg.getHeight(), 0, 0, inputImg.getWidth(), inputImg.getHeight(), null);
// print
app.print(outputImg, outputImg.getWidth(), outputImg.getHeight());
}
}
Execution produces the following output:
0 1
131072 131073
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
Seems like Graphics2D object works, because I'm able to draw, for example, a line calling the drawLine function. So, I think the inputImg is the source of the issue, but I can't figure out what's wrong.
UPDATE:
I've tried to use AffineTransform, but it didn't help, unfortunately.
Graphics2D g = outputImg.createGraphics();
AffineTransform at = new AffineTransform();
at.setToIdentity();
at.scale(2, 2);
g.drawImage(inputImg, at, null);
To me, this seems to be an issue with the color calculation you're using...
When I change...
inputImg.setRGB(x, y, y * inputWidth * (1 << 16) + x);
to...
int rgb = y * inputWidth * (1 << 16) + x;
inputImg.setRGB(x, y, new Color(rgb).getRGB());
I get a result, albeit a black dot. This suggests to me that by default, your calculation is generating a alpha value of 0
This can be born out in the output that they produce:
My method generates
-16777216 -16777215
-16646144 -16646143
Yours generates
0 1
131072 131073
Now, frankly, this is why I don't do this kind of calculation, not when a API is available to do it for me - but I be dumb ;P
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class Main {
public void print(BufferedImage img, int width, int height) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
System.out.print(img.getRGB(x, y) + " ");
}
System.out.println("");
}
}
public static void main(String[] args) {
Main app = new Main();
// create input image
int inputWidth = 2;
int inputHeight = 2;
BufferedImage inputImg = new BufferedImage(inputWidth, inputHeight, BufferedImage.TYPE_INT_ARGB);
// fill input image
System.out.println(inputWidth + "x" + inputHeight);
Color color = Color.RED;
for (int y = 0; y < inputHeight; y++) {
for (int x = 0; x < inputWidth; x++) {
int rgb = y * inputWidth * (1 << 16) + x;
inputImg.setRGB(x, y, new Color(rgb).getRGB());
}
}
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(inputImg)));
// print
app.print(inputImg, inputWidth, inputHeight);
// create output image
int outputWidth = 4;
int outputHeight = 4;
BufferedImage outputImg = new BufferedImage(outputWidth, outputHeight, BufferedImage.TYPE_INT_ARGB);
// draw inputImg into outputImg
Graphics2D g = outputImg.createGraphics();
g.drawImage(inputImg, 0, 0, outputImg.getWidth(), outputImg.getHeight(), 0, 0, inputImg.getWidth(), inputImg.getHeight(), null);
g.dispose();
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(outputImg)));
// print
app.print(outputImg, outputImg.getWidth(), outputImg.getHeight());
}
}

Java Greyscale buffered image

So I have a byte array representing pixel data (8bit grayscale). No header. No nothing. Just the data. I want to create a buffered image from this data. I did
image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, w, h, data);
this.x = w;
this.y = h;
scalemode=false;
exactmode=true;
where w is just width in pixel,h is height in pixel,data is the byte array and image is BufferedImage
here is my paint method
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int rx = (this.getWidth() - x) / 2;
int ry = (this.getHeight() - y) / 2;
g2d.drawImage(image, rx, ry,x,y, null);
}
I, however, get this image (the real image is a fingerprint, which is mostly white pixel)
What went wrong? I tried saving the data as is and then viewing it in Photoshop. The data is fine.
[edit]
Never mind this problem. I fucked up in other part of the code and was not aware. Thank you for all inputs though
It's hard to know exactly what is wrong, as you haven't posted enough information. We don't know w, h or what information is in your data. We don't know what the image should look like.
However, here's some code that does pretty much exactly what you are doing, and it works for me:
// Set up h/w and backing data
int w = 300;
int h = 200;
byte[] data = new byte[w * h];
// Create a smooth gradient
for (int y = 0; y < h; y++) {
int off = y * w;
for (int x = 0; x < w; x++) {
data[off + x] = (byte) (Math.round((x / (double) w) * 127)
+ Math.round((y / (double) h) * 127));
}
}
// Create BufferedImage from data
final BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, w, h, data);
// Show it all in a window
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame(getClass().getSimpleName());
frame.add(new JLabel(new ImageIcon(image)));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
Here is the result:
draw every byte on each pixel...
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
for (int dy = 0; dy < h; dy ++){
for(int dx = 0; dx < w; dx ++){
int index = dy*w + dx;
int rgb = data[index];
rgb = rgb << 24 & 0xFFFF; //BufferedImage.TYPE_BYTE_GRAY consideres only the red-channel;
//rgb = 00 data[index] FF FF
image.setRGB(dx,dy,rgb);
}
}
}
you didn't set up your Buffer properly...
byte[] data = ...
DataBufferByte db = new DataBufferByte(data, w*h);
image.getRaster().setDataElements(0, 0, w, h, db );
see http://docs.oracle.com/javase/7/docs/api/java/awt/image/WritableRaster.html#setDataElements%28int,%20int,%20java.lang.Object%29

Categories

Resources