Reputation: 125
EDIT: I've changed some of my code to reflect what AlamasB said. I still don't understand how I should be populating my byte array and what conversions I need to do.
I'm trying to manipulate the pixels of an image uploaded by the user and write the new image onto a canvas. Right now I'm just trying to copy the original image without changing the RGB of the pixels. I've been stuck in the same spot for quite a while now and can't figure out where to go next. In the first section of the code I make a copy of the original image uploaded by the user.
Image image = imageView.getImage();
PixelReader pixelReader = image.getPixelReader();
PixelFormat format = pixelReader.getPixelFormat();
int width= (int)image.getWidth();
int height = (int) image.getHeight();
GraphicsContext gc = canvas.getGraphicsContext2D();
PixelWriter pw = gc.getPixelWriter();
byte[] imageData = new byte[width * height * 4];
imageData = createImageData(imageData, pixelReader, width, height);
//..
//...the next function populates my byte array with what's in the image
public byte[] createImageData(byte[] imageData, PixelReader pr, int width, int height){
int i = 0;
for(int y=0; y<height; y++){
for(int x = 0; x < width; x++){
int argb = pixelReader.getArgb(x, y);
imageData[i] = (byte) argb;
imageData[i+1] = (byte) argb;
imageData[i+2] = (byte) argb;
i+=3;
pw.setArgb(x, y, argb);
}
}
return imageData;
}
EDIT: No longer using this function. The next function is really confusing me. I'm referring to this http://docs.oracle.com/javafx/2/image_ops/jfxpub-image_ops.htm as a reference but I can't figure out what's going on.
//...
//... the next function sets the pixels of the canvas to what's in the byte array
public void drawImageData(byte[] imageData, PixelWriter pw, int width, int height){
boolean on = true;
PixelFormat<ByteBuffer> pixelFormat = PixelFormat.getByteRgbInstance();
for(int y = 50; y < 150; y+=height){
for(int x = 50; x < 150; x+=width){
if(on){
pw.setPixels(x, y, width, height, pixelFormat, imageData, 0, width*3);
}
on = !on;
}
on=!on;
}
}
Upvotes: 1
Views: 2008
Reputation: 3407
Considering that PixelReader
provides getARGB your best bet in this case is probably to use 32-bit representation. Subsequently converting it to a 4-byte array, i.e. width * height * 4
. Finally use setARGB to draw the image.
int argb = pixelReader.getArgb(x, y);
// populate imageData[i,i+1,i+2,i+3] by converting argb
...
// convert imageData[i,i+1,i+2,i+3] into a 32bit argb, say int argb2
pixelWriter.setArgb(x, y, argb2);
Alternatively, you can use Color's getOpacity()
to get the A
from RGBA
. Again, using the 32-bit representation.
At the very least this will provide you with a minimal working example, which you can then extend.
Here's a quick version (self-contained, just copy and paste):
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.*;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.nio.ByteBuffer;
import java.util.Arrays;
public class ImageManipulationApp extends Application {
private static final int APP_W = 800;
private static final int APP_H = 600;
private Parent createContent() {
Image image = makeMockImage();
byte[] imageData = imageToData(image);
byte[] modifiedImageData = modify(imageData);
Image modifiedImage = dataToImage(modifiedImageData);
HBox root = new HBox(25);
root.getChildren().addAll(new ImageView(image), new ImageView(modifiedImage));
return root;
}
private Image makeMockImage() {
WritableImage image = new WritableImage(APP_W / 2, APP_H);
PixelWriter writer = image.getPixelWriter();
for (int y = 0; y < APP_H; y++) {
for (int x = 0; x < APP_W / 2; x++) {
writer.setColor(x, y, Math.random() < 0.00005 ? Color.YELLOW : Color.BLACK);
}
}
return image;
}
/**
* Modifies the pixel data.
*
* @param data original image data
* @return modified image data
*/
private byte[] modify(byte[] data) {
// this is where changes happen
return data;
}
private byte[] imageToData(Image image) {
int width = (int) image.getWidth();
int height = (int) image.getHeight();
byte[] data = new byte[width * height * 4];
int i = 0;
for (int y = 0; y < height; y++){
for (int x = 0; x < width; x++){
int argb = image.getPixelReader().getArgb(x, y);
byte[] pixelData = ByteBuffer.allocate(4).putInt(argb).array();
data[i++] = pixelData[0];
data[i++] = pixelData[1];
data[i++] = pixelData[2];
data[i++] = pixelData[3];
}
}
return data;
}
private Image dataToImage(byte[] data) {
// if we don't know the image size beforehand we can encode width and height
// into image data too
WritableImage image = new WritableImage(APP_W / 2, APP_H);
PixelWriter writer = image.getPixelWriter();
int i = 0;
for (int y = 0; y < APP_H; y++) {
for (int x = 0; x < APP_W / 2; x++) {
int argb = ByteBuffer.wrap(Arrays.copyOfRange(data, i, i + 4)).getInt();
writer.setArgb(x, y, argb);
i += 4;
}
}
return image;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 1