I´m reading a simple jpg image with Java and printing out a 2d array of the pixel data.
If I have the entire image black I get what I expect:
This is the 10x20 black image
And the result:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
However if I draw a white line on the first row of the image I'm getting 1's in a place I don´t expect:
The other image:
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 //Why??
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
This is my code:
byte[][]pixels;
BufferedImage image;
public ImageProcessor(File f) throws IOException{
image = ImageIO.read(f);
//Bitmap bMap = BitmapFactory.decodeFile(f.getAbsolutePath()); // Si es jpg
pixels = new byte[image.getWidth()][];
for (int x = 0; x < image.getWidth(); x++) {
pixels[x] = new byte[image.getHeight()];
for (int y = 0; y < image.getHeight(); y++) {
pixels[x][y] = (byte) (image.getRGB(x, y));
}
}
}
public void printPixelMatrix(){
for (int i = 0; i < image.getHeight(); i++) {
for (int j = 0; j < image.getWidth(); j++) {
System.out.print(" "+pixels[j][i] + " ");
}
System.out.print("\n");
}
}
I don't use Java so I'm going on general computer graphics knowledge...
1) Firstly, You might want to set a type for your buffered image (ie: 4 byte where you have 1 byte for each component of R + G + B + Alpha). Something like BufferedImage.TYPE_INT_ARGB.
2) I don't get why you try to put the result of image.getRGB(x, y) into a byte. From Java docs it seems getRGB(x, y) returns an array not a single number and even then, that number would have combined all A-R-G-B as one but a byte can only hold one component's value as max amount (up to 255, but a color int could be like 4278254335 spread over 4 bytes).
suggested solution : Instead of bytes (and strides?), just scan the pixels and get an int of the pixel value. Then print those values. Black = 0 and also White = 4278254335. I think I got the Hex format code okay below, so that should show as : Black = FF000000 and then White = FFFFFFFF.
I think your final code should work something like as shown below. Please fix any mistakes (I put comments so you see what I am trying to do). That should give you the expected colours of the black, or black with white line, in the expected positions :
//# load your old one as usual
image = ImageIO.read(f);
//# Create a new bufferdImage with type (will draw old into this) //also consider TYPE_INT_RGB
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
//# Then draw original into new type...
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
g.dispose(); //needed or not???
//# Doing the For-loop
int imgW = image.getWidth();
int imgH = image.getHeight();
int pixels[][] = new int[imgW][imgH]; //create a 2D array
//# Fill Array : for each [x] pos we read down /column
//# so that we fill [y] with those pixel values
for (int x = 0; x < imgW; x++)
{
//On each X pos we scan all Y pixels in that column
for (int y = 0; y < imgH; y++)
{
int col = image.getRGB(x, y);
pixels[x][y] = col;
//printPixelARGB( col ); //if you need this format instead of printPixelMatrix
}
}
//# To Print output
public void printPixelMatrix()
{
for (int i = 0; i < image.getHeight(); i++)
{
for (int j = 0; j < image.getWidth(); j++)
{
//System.out.print(" " + pixels[j][i] + " ");
int c = pixels[j][i]; //get integer that was stored in the array
String HexVal = Integer.toHexString( c ) //giveshex value like AARRGGBB
System.out.print(" " + HexVal + " ");
}
System.out.print("\n");
}
}
//# Another helper function to print pixel values
//# print out example blue : argb: 255, 0, 0, 255
public void printPixelARGB(int pixel)
{
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
System.out.println("ARGB : " + alpha + ", " + red + ", " + green + ", " + blue);
}
Java doesn't have unsigned types, so your "white" pixels, which are the maximum value (0xff), are interpreted as negative 1.
Presumably your positive 1s are a compression artifact.
I suspect you are getting an artifact from JPEG quantization. JPEG compresses square blocks of pixels, not individual pixels.
See if there is a way to change your quantization tables. If you make them all 1 values, this should go away. Some encoders use "quality" settings for this. Use the highest quality setting.
Related
I need to print the a ppm picture but the output isn't organized as it should be, my code:
public static int[][][] read(String filename) {
StdIn.setInput(filename);
StdIn.readLine();
int imgW = StdIn.readInt ();
int imgH = StdIn.readInt ();
int[][][] data = new int[imgH][imgW][3];
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
for (int k = 0; k < data[i][j].length; k++) {
data[i][j][k] = StdIn.readInt();
}
}
}
return data;
}
my output:
255 0 0 0 100 0 0 0 0 0 255 0
255 0 0 0 0 255 175 0 0 0 0 0
0 0 0 0 0 0 0 0 15 175 0 0
0 255 0 255 0 0 0 0 0 0 255 255
the correct output: (basically same like a matrix)
0 0 0 100 0 0 0 0 0 255 0 255
0 0 0 0 255 175 0 0 0 0 0 0
0 0 0 0 0 0 0 15 175 0 0 0
255 0 255 0 0 0 0 0 0 255 255 255
Ppm files also lists the maximum value appearing in the file, which is the 255 in the beginning of your output.
You should add an extra StdIn.readInt(); before your loop.
On the program I am working on I have to find a letter pair contained in an unspecified amount of input. If two consecutive English letters that are the same, case-insensitive, are found, then I add one to an element within my 2d array that is 26 rows by 26 columns. Here is my code:
import java.util.Scanner;
public class Freq{
private static final int ROWS = 26;
private static final int COLS = 26;
private static int[] [] alphabet = new int[ROWS][COLS];
public static void main(String[] args) {
String line;
Scanner userInput = new Scanner(System.in);
while(userInput.hasNextLine()) {
line = userInput.nextLine();
processLine(line);
}
printArray();
}
public static void processLine(String line) {
line = line.toUpperCase();
for(int i = 0; i < alphabet.length; i++) {
for(int j = 0; j < alphabet[i].length; j++) {
for (int a = 0; a < line.length() - 1; a++) {
char firstLetter = line.charAt(a);
char secondLetter = line.charAt(a + 1);
if (firstLetter == secondLetter) {
alphabet[firstLetter - 65][secondLetter - 65] += 1;
}
}
}
}
}
public static void printArray() {
for (int b = 0; b < alphabet.length; b++) {
for (int c = 0; c < alphabet[b].length; c++){
System.out.print(alphabet[b][c] + " ");
}
System.out.println();
}
}
}
However when I run my program and input "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz"
this is what happens:
aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz
676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 676
I believe they are being added in the correct location, but why is my program adding 676 to the index and not just adding 1? Any help is greatly appreciated. Thank you!
Your processLine() method does not make much sense. First, you should only be iterating over the input string, and not the entire 2D array, i.e.:
public static void processLine(String line) {
line = line.toUpperCase();
for (int a=0; a < line.length() - 1; a++) {
char firstLetter = line.charAt(a);
char secondLetter = line.charAt(a + 1);
if (firstLetter == secondLetter) {
alphabet[firstLetter - 65][secondLetter - 65] += 1;
}
}
}
Second, your 2D array will only ever have entries on the diagonal, because you only ever make assignments where the two characters are the same for both dimensions. So you could just use a 1D array:
private static int[] alphabet = new int[ROWS];
public static void processLine(String line) {
line = line.toUpperCase();
for (int a=0; a < line.length() - 1; a++) {
char firstLetter = line.charAt(a);
char secondLetter = line.charAt(a + 1);
if (firstLetter == secondLetter) {
alphabet[firstLetter - 65] += 1;
}
}
}
What your are doing is that you are adding value from that position on matrix with 1 instead if you want 1 at that place just assign it
Replace this line
alphabet[firstLetter - 65][secondLetter - 65] += 1;
with this
alphabet[firstLetter - 65][secondLetter - 65] = 1;
or change your processLine method to this
public static void processLine(String line) {
line = line.toUpperCase();
for (int a = 0; a < line.length() - 1; a++) {
char firstLetter = line.charAt(a);
char secondLetter = line.charAt(a + 1);
if (firstLetter == secondLetter) {
alphabet[firstLetter - 65][secondLetter - 65] += 1;
}
}
}
hope this answer your question
I am making a scrolling game in Java , I would like a clarification on one point.
I do not save the game level in any structure java , I just read a file ( . gif )
which I modified in a way that :
I use the color decryption to parse through every pixel to pixel and place where the
object meets the requirements that I have established .
for example:
.
.
.
int w = image.getWidth(); //store the dimensions of the level image.
int h = image.getHeight();
for(int x = 0; x < w; x++){
for(int y = 0; y < h; y++){ //check every single pixel with this nested loop
int pixel = image.getRGB(x, y); //get the pixel's rgb value
TYPE_INT_ARGB formatint red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
if(red == 255 && green == 255 && blue == 0)
controller.addPlayer((float)x, (float)y);
else if(red == 255 && green == 255 && blue == 255)
controller.addTerrain(x, y);
}
as you can see i don't save the level in any structure, but I just scan the image file that represents it.
is a good idea to do it this way?
Naturally i store all objects with the controller class where i create an arrayList that contains all game 's objects .
You could make a .txt file and create a map like this:
20
10
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0
the 0 would represent air and the 1 a walkable tile. the first value is the map width and the second the map height.
I also recommend you to use a 2d array to store the map information. Now you can read the txt file with a BufferedReader. Hope this code below helps
private final int TILE_SIZE = 30;
private int[][] blocks;
private void loadMap(File file) {
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
mapWidth = Integer.parseInt(reader.readLine());
mapHeight = Integer.parseInt(reader.readLine());
blocks = new int[mapHeight][mapWidth];
for(int col = 0; col < mapHeight; col ++) {
String line = reader.readLine();
String[] tokens = line.split(" ");
for(int row = 0; row < numBlocksRow; row++) {
blocks[col][row] = Integer.parseInt(tokens[row]);
}
}
reader.close();
} catch(Exception e) {
e.printStackTrace();
}
}
private void render(Graphics2D g) {
for(int col = 0; col < mapHeight; col ++) {
for(int row = 0; row < numBlocksRow; row++) {
int block = blocks[col][row];
Color color;
if(block == 1) {
color = Color.white;
} else {
color = Color.black;
}
g.fillRect(row * TILE_SIZE, col * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
}
}
Recently I've been trying to make a little game for my learning purpose but I got stuck. I was able to generate a map from a .txt file but then it seems to paint it sideways?
this is my map loaded which reads from a text file and add them to an ArrayList.
Width is 20 Height is 10. Same thing applies in my map 20 lines wide 10 down.
public void loadMap(String name) {
try {
this.name = name;
FileInputStream file_stream = new FileInputStream(name);
DataInputStream in = new DataInputStream(file_stream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
map = new Tile[WIDTH][HEIGHT];
String line;
int y = 0;
while ((line = br.readLine()) != null) {
String[] tokens = line.split(" ");
for (int x = 0; x < WIDTH; x++) {
boolean f = false;
if (Integer.parseInt(tokens[x]) == 1)
f = true;
Tile tile = new Tile(y, x, f, Integer.parseInt(tokens[x]));
tiles.add(tile);
map[x][y] = tile;
System.out.println("adding tile (x: " + x + " y: " + y + ") " + f + " " + Integer.parseInt(tokens[x]));
}
y++;
}
in.close();
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "The map: " + name + " was not found.");
e.printStackTrace();
}
}
This is the draw method for the map
public void paint(Graphics2D g) {
for (Tile t : getTiles()) {
t.draw(g);
//g.draw(t.getBounds());
}
}
Here is an example map
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
The way it paints the map is basically a vertical version of this instead of the correct way like it is above. I have tried messing with the numbers within the mapLoaded (width, height) and switching the x and y around but nothing seems to work. Please help
You simply need to change Tile tile = new Tile(y, x, f, Integer.parseInt(tokens[x])); to
Tile tile = new Tile(x, y, f, Integer.parseInt(tokens[x]));.
Everytime you're making a new Tile, you're switching x and y which is causing your problems.
Well I've created a simple tile map loading, from .txt file & then drawing.
25
15
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
So if the current tile is 1, it will be a green block.
Now the game window looks like this (ignore yellow dots at top):
(source: gyazo.com)
Okay everything is fine and great, but now can you see the red box? that's the character, and when it walks, I don't want it to go over the gates (any green block).
How can I do that?
My attempt:
private void makeClips() {
int[][] tiledMap = this.map.getMap();
for (int i = 0; i < this.map.getHeight(); i++) {
for (int j = 0; j < this.map.getWidth(); j++) {
if (tiledMap[i][j] == 1) {
clips.add(new Clip(j * 30, i * 30, 0, 0));
System.out.println("Added clip: " + j + " " + i + " " + (j + 30) + " " + (i + 30));
}
}
}
}
That should create an array of clips, so we can check if player's next walk equals to the clips coordinates, but I've had problems with setting the clip x, y like what will it's position be.
The 30 is the tile size, so each block will be 30 width 30 height sized.
And then in the walking method i've done this:
for (Clip clip : clips) {
if (myPlayer.getX() + x >= clip.getFirstX() && myPlayer.getX() + x <= clip.getSecX()
&& myPlayer.getY() + y >= clip.getFirstY() && myPlayer.getY() + y <= clip.getSecY()) {
System.out.println("Bad");
return;
}
}
But I don't know, this is 100% incorrect, mostly the coordinate calculating part.
What would you do in this case?
This is the drawing part for map:
private void renderMap(Graphics2D g) {
int[][] tiledMap = this.map.getMap();
for (int i = 0; i < this.map.getHeight(); i++) {
for (int j = 0; j < this.map.getWidth(); j++) {
int currentRow = tiledMap[i][j];
if (currentRow == 1) {
g.setColor(Color.green);
}
if (currentRow == 0) {
g.setColor(Color.black);
}
g.fillRect(0 + j * map.getTileSize(), 0 + i * map.getTileSize(),
map.getTileSize(), map.getTileSize());
g.setColor(Color.yellow);
for (Clip clip : clips) {
g.fillRect(clip.getFirstX(), clip.getFirstY(), 2, 2);
}
}
}
}
What can I do?
Why not do a check every time you move your player on the tile you want to move him onto.
Lets assume the player is at (0,0) on this small map.
0 0 1
0 0 0
0 0 0
We will try and move him to the right twice. The first time will work as at the position (1,0) the tile is equal to 0. The second time we try this the tile at (2,0) will return 1 and the player won't move.
if (tiledMap[player.getX() + 1)[player.getY()] == 1) {
//do nothing
} else {
//move player
}