I have a problem with getting gray scale of a .jpg file. I am trying to create a new .jpg file as gray scaled but I am just copying the image nothing more. Here is my code:
package training01;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class GrayScale {
BufferedImage image;
int width;
int height;
public GrayScale() {
try {
File input = new File("digital_image_processing.jpg");
image = ImageIO.read(input);
width = image.getWidth();
height = image.getHeight();
for(int i = width;i < width;i++) {
for(int j = height;j < height;j++) {
Color c = new Color(image.getRGB(i, j));
int red = c.getRed();
int green = c.getGreen();
int blue = c.getBlue();
int val = (red+green+blue)/3;
Color temp = new Color(val,val,val);
image.setRGB(i, j, temp.getRGB());
}
}
File output = new File("digital_image_processing1.jpg");
ImageIO.write(image, "jpg", output);
}catch(Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
GrayScale gs = new GrayScale();
}
}
You need to change the following. Start your i and j at 0.
for(int i = width;i < width;i++) {
for(int j = height;j < height;j++) {
However, here is a faster way to do it. Write it to a new BufferedImage object that is set for gray scale.
image = ImageIO.read(input);
width = image.getWidth();
height = image.getHeight();
bwImage = new BufferedImage(width,
height, BufferedImage.TYPE_BYTE_GRAY);
Graphics g = bwImage.getGraphics();
g.drawImage(image,0,0,null);
Then save the bwImage.
The main problem with your code, is that it won't loop, because you initialize i, j to width, height which is already greater than the exit condition of the for loops (i < width, j < height). Start iterating at 0 by initializing i and j to 0, and your code will work as intended.
For better performance, you also want to change the order of the loops. As BufferedImages are stored as a continuous array, row by row, you will utilize the CPU cache much better if you loop over the x axis (row) in the inner loop.
Side note: I also suggest renaming i and j to x and y for better readability.
Finally, your method of converting RGB to gray by averaging the colors will work, but is not the most common way to convert to gray scale, as the human eye does not perceive the intensities of the colors as the same. See Wikipedia on gray scale conversion for a better understanding of correct conversion and the theory behind it.
However, all of this said, for JPEG images stored as YCbCr (the most common way to store JPEGs), there is a much faster, memory efficient and simpler way of converting the image to gray scale, and that is simply reading the Y (luminance) channel of the JPEG and use that as gray scale directly.
Using Java and ImageIO, you can do it like this:
public class GrayJPEG {
public static void main(String[] args) throws IOException {
try (ImageInputStream stream = ImageIO.createImageInputStream(new File(args[0]))) {
ImageReader reader = ImageIO.getImageReaders(stream).next(); // Will throw exception if no reader available
try {
reader.setInput(stream);
ImageReadParam param = reader.getDefaultReadParam();
// The QnD way, just specify the gray type directly
//param.setDestinationType(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY));
// The very correct way, query the reader if it supports gray, and use that
Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
while (types.hasNext()) {
ImageTypeSpecifier type = types.next();
if (type.getColorModel().getColorSpace().getType() == ColorSpace.TYPE_GRAY) {
param.setDestinationType(type);
break;
}
}
BufferedImage image = reader.read(0, param);
ImageIO.write(image, "JPEG", new File(args[0] + "_gray.jpg"));
}
finally {
reader.dispose();
}
}
}
}
Related
What I have:
I have 2 images with same size (500), one is a normal image and the other have a message with only black pixels (message) and white pixels (nothing).
What i do in encodeImage() is create messageEncoded with pixels of originalImage and incrementing it by 1 if the pixel of the messageImage isn't white.
This is how i'm hidding a image in another image, so decodeImage() should read the originalImage and messageEncoded to extract the messageImage, creating messageDecoded with white pixel when doens't change the pixel and black and it changes.
PImage originalImage;
PImage messageImage;
PImage messageEncoded;
PImage messageDecoded;
void setup() {
size(500, 500);
originalImage = loadImage("jap.jpg");
messageImage = loadImage("msg.jpg");
messageEncoded = createImage(originalImage.width, originalImage.height, RGB);
messageDecoded = createImage(originalImage.width, originalImage.height, RGB);
encodeImage();
}
void decodeImage() {
originalImage.loadPixels();
messageEncoded.loadPixels();
messageDecoded.loadPixels();
PImage msg = loadImage("messageEncoded.jpg");
msg.loadPixels();
for (int x = 0; x < originalImage.width; x++) {
for (int y = 0; y < originalImage.height; y++ ) {
int loc = x + y * originalImage.width;
if (messageEncoded.pixels[loc] == originalImage.pixels[loc]) {
messageDecoded.pixels[loc] = color(255);
} else {
messageDecoded.pixels[loc] = color(0);
}
}
}
messageDecoded.updatePixels();
messageDecoded.save("messageDecoded.jpg");
image(messageDecoded, 0, 0);
}
void encodeImage() {
originalImage.loadPixels();
messageImage.loadPixels();
messageEncoded.loadPixels();
for (int x = 0; x < originalImage.width; x++) {
for (int y = 0; y < originalImage.height; y++ ) {
int loc = x + y * originalImage.width;
if (messageImage.pixels[loc] != color(255)) {
float r = red(originalImage.pixels[loc]);
float g = green(originalImage.pixels[loc]);
float b = blue(originalImage.pixels[loc]);
messageEncoded.pixels[loc] = color(r + 1, g + 1, b + 1);
} else {
messageEncoded.pixels[loc] = originalImage.pixels[loc];
}
}
}
messageEncoded.updatePixels();
messageEncoded.save("messageEncoded.jpg");
//image(messageEncoded, 0, 0);
decodeImage();
}
The Problems:
I have the variable PImage msg in void decodeImage() that I'm not using. This variable should be the same as the global messageEncoded because it's reading the file that it just outputed, but if I use msg, changing
if (messageEncoded.pixels[loc] == originalImage.pixels[loc]) {
messageDecoded.pixels[loc] = color(255);
} else {
messageDecoded.pixels[loc] = color(0);
}
into
if (msg.pixels[loc] == originalImage.pixels[loc]) {
messageDecoded.pixels[loc] = color(255);
} else {
messageDecoded.pixels[loc] = color(0);
}
the result is totally different and weird. Why? What is the difference between messageEncoded and msg?
messageDecoded is a little bit wrong, why it's having this wrong black dots?
I made the messageImage in paint, so i though paint is creating non-black dots, but i look all pixels, even put a single black pixel and still appeared some black dots around it.
The originalImage. I found this on google by typing '500x500 images'.
The messageImage. I created this on paint and save it with 500x500 dimentions (for testing it can be and draw with only black and with pixels).
The very weird picture that happens when I use msg. (Problem 1)
The messageDecoded the have black dots around it. Can I call it noise? (Problem 2)
Edit 1:
The weird image and the problem 1 is solved when I use PNG images, but the 2 problem of the "noise" isn't fixed yet
It's likely that JPEG encoding is causing the problem (the noise looks characteristic of compression artifacts). You'll need to work with images in a lossless format such as .PNG to alleviate the problem.
Recreate messageImage, saving it as a .PNG this time.
Convert originalImage to .PNG and modify your code such that
Processing saves the images as .PNG.
It's ok to use a JPEG as the source image; the problem arises from successive JPEG saving/encoding (where more pixels than simply those which are being encoded are changed).
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 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).
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 :)
}
Is there a fast way in Java to replace all instances in a bitmap of certain colors with other colors?
The image I am working with is a single very large 5616 x 2160 24bit non-transparent unindexed bitmap, although the pixel values of this bitmap will vary.
This is the code I am using at the moment, but it is much too slow:
http://pastebin.com/UjgwgB0V
public class DisplayImage extends JFrame {
public DisplayImage(boolean resize, boolean mapCountries) throws IOException {
super("Province Map");
File mapProvinceFile = new File("map\\provinces.bmp");
BufferedImage mapProvinceImage = ImageIO.read(mapProvinceFile);
byte[] pixels = (byte[])mapProvinceImage.getRaster().getDataElements(0, 0, mapProvinceImage.getWidth(), mapProvinceImage.getHeight(), null);
if (mapCountries) {
for (int i = 0; i < Victoria2Stats.provinceDefinitionArray.size(); i++) {
for (int p = 0; p < pixels.length-3; p = p + 3) {
if ((byte)Victoria2Stats.provinceDefinitionArray.get(i).rgb[0] == pixels[p]) {
if ((byte)Victoria2Stats.provinceDefinitionArray.get(i).rgb[1] == pixels[p+1]) {
if ((byte)Victoria2Stats.provinceDefinitionArray.get(i).rgb[2] == pixels[p+2]) {
try {
if ((Victoria2Stats.provinceDataTable[i].ownerColor == null) && !(Victoria2Stats.provinceDataTable[i].lifeRating == 0)) {
pixels[p] = (byte)255;
pixels[p+1] = (byte)255;
pixels[p+2] = (byte)255;
} else {
pixels[p] = (byte)(Victoria2Stats.provinceDataTable[i].ownerColor.getRed());
pixels[p+1] = (byte)(Victoria2Stats.provinceDataTable[i].ownerColor.getBlue());
pixels[p+2] = (byte)(Victoria2Stats.provinceDataTable[i].ownerColor.getGreen());
}
} catch (NullPointerException e) {
// I realise this is a bad practice, but it is unrelated to the question and will be fixed later
}
}
}
}
}
}
}
BufferedImage buffer = new BufferedImage(mapProvinceImage.getWidth(), mapProvinceImage.getHeight(), mapProvinceImage.getType());
DataBuffer dataBuffer = new DataBufferByte(pixels, pixels.length);
SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_BYTE, mapProvinceImage.getWidth(), mapProvinceImage.getHeight(), 3, mapProvinceImage.getWidth()*3, new int[]{0,1,2});
Raster raster = Raster.createRaster(sampleModel, dataBuffer, null);
buffer.setData(raster);
BufferedImage fixedImage = ImageUtils.verticalflip(buffer);
ImageIcon ii = new ImageIcon(fixedImage);
JScrollPane jsp = new JScrollPane(new JLabel(ii));
getContentPane().add(jsp);
setSize(800, 600);
setVisible(true);
}
}
Here is an example image: http://www.mediafire.com/?rttpk4o33b3oj74
I was thinking of somehow converting it to an indexed bitmap and then swapping the color indexes, but I couldn't figure out any way to successful assign it/recreate it with a color index with Java.
An instance of java.awt.image.LookupOp with a suitable LookupTable may be faster. An example is cited here.
ColorConvertOp, illustrated here, would require a suitable ColorSpace.
ImageJ, mentioned here, can be used for batch processing.
If you want to do this really fast, the best way is to access the underlying pixel data:
int[] data = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
Then you should write your algorithm so that it does exactly one pass through this array, testing each int and changing it if necessary.
This approach should be as fast as native code.
I actually think you should try using Processing (www.processing.org) . I was able to do a simple color change for your image with very little code:
import processing.opengl.PGraphics3D;
//place provinces.bmp in the PROJECTFOLDER/data
PImage p = loadImage("provinces.bmp");
//This just changes the window size, but the full image will be loaded
size(1000,800,P2D);
PGraphics big = createGraphics(p.width, p.height, P2D);
big.beginDraw();
big.image(p,0,0);
//BEGIN GRAPHICS MANIPULATION
big.loadPixels();
for (int i = 0; i < big.pixels.length; i++) {
color c = color(big.pixels[i]);
float r = red(c);
float g = green(c);
float b = blue(c);
//Let's do a simple color change, keeping r the same, setting green equal to old b, and setting blue to 0
big.pixels[i] = color(r,b,0);
}
//END GRAPHICS MANIPULATION
big.updatePixels();
big.endDraw();
String path = savePath("big.jpg"); //change to tif or something else for uncompressed
big.save(path);
image(big, 0, 0);
Leave a comment if you need some advice on how to do different color mappings, but you can change the code around the comment ("Let's do a simple color change")
Now obviously this is probably not the exact color change you want, but here is the result of the above code: http://www.kapparate.com/hw/big.jpg
FYI you can use PImage and PGraphics in a non-processing Java app by include core.jar from processing in your java classpath
General comments:
Your idea of converting to an indexed bitmap is unlikely to help, because (I think you will find that) conversion cost exceeds the saving.
You may do better solving the problem using an external application or a native code library.
I think there is scope for micro-optimization. For example:
public class DisplayImage extends JFrame {
public DisplayImage(boolean resize, boolean mapCountries)
throws IOException {
super("Province Map");
File mapProvinceFile = new File("map\\provinces.bmp");
BufferedImage mapProvinceImage = ImageIO.read(mapProvinceFile);
byte[] pixels = (byte[])mapProvinceImage.getRaster().getDataElements(
0, 0, mapProvinceImage.getWidth(), mapProvinceImage.getHeight(), null);
if (mapCountries) {
int len = Victoria2Stats.provinceDefinitionArray.size();
for (int i = 0; i < len; i++) {
int[] rgb = Victoria2Stats.provinceDefinitionArray.get(i);
ProvinceDataTable pdt = Victoria2Stats.provinceDataTable[i];
for (int p = 0; p < pixels.length-3; p = p + 3) {
if ((byte) rgb[0] == pixels[p] &&
(byte) rgb[1] == pixels[p+1] &&
(byte) rgb[2] == pixels[p+2]) {
if (pdt.ownerColor == null && pdt.lifeRating != 0) { // HERE
pixels[p] = (byte)255;
pixels[p+1] = (byte)255;
pixels[p+2] = (byte)255;
} else {
pixels[p] = (byte)(pdt.ownerColor.getRed());
pixels[p+1] = (byte)(pdt.ownerColor.getBlue());
pixels[p+2] = (byte)(pdt.ownerColor.getGreen());
}
}
}
}
}
BufferedImage buffer = new BufferedImage(
mapProvinceImage.getWidth(), mapProvinceImage.getHeight(),
mapProvinceImage.getType());
DataBuffer dataBuffer = new DataBufferByte(pixels, pixels.length);
SampleModel sampleModel = new ComponentSampleModel(
DataBuffer.TYPE_BYTE, mapProvinceImage.getWidth(),
mapProvinceImage.getHeight(), 3, mapProvinceImage.getWidth()*3,
new int[]{0,1,2});
Raster raster = Raster.createRaster(sampleModel, dataBuffer, null);
buffer.setData(raster);
BufferedImage fixedImage = ImageUtils.verticalflip(buffer);
ImageIcon ii = new ImageIcon(fixedImage);
JScrollPane jsp = new JScrollPane(new JLabel(ii));
getContentPane().add(jsp);
setSize(800, 600);
setVisible(true);
}
}
IMO, the improvement in readability makes this worthwhile even if it doesn't improve performance. Fixing the indentation helps too!
Incidentally, once I removed all of the verbiage, the probable source of your NPE problems became more obvious. Look at the line that I labelled "HERE". Note that the condition is such that the "then" branch is only taken if the ownerColor is null AND the lifeRating is non-zero. If the ownerColor is null AND the lifeRating is zero, you will take the "else" branch and an NPE is inevitable.