JavaFx Displaying Images from pixel array - image

I changed pixel array of an image, and I want to display it.
I tried this code (below), but it's doesn't work.
int[] pixelSrcImage;
PixelGrabber pgSrc =
new PixelGrabber(imageSrc, 0, 0, imageHeight, imageWidth, pixelSrcImage, 0,imageWidth);
pgSrc.grabPixels();
pixelSrcImage[...]=...
PixelWriter pw = null;
WritablePixelFormat<IntBuffer> format = WritablePixelFormat.getIntArgbInstance();
pw.setPixels(0, 0, imageWidth, imageHeight, format, step, 0, imageWidth);
Image imView = new Image (pw.???);

You need to define the destination image first and not set the PixelWriter to null.
WritableImage image = new WritableImage(width, height);
PixelWriter pw = image.getPixelWriter();
All I can see from your bits & pieces is that you'll get a NullPointer Exception.
And please consider what jewelsea said.

Related

Convert JavaFX Image object to byte array

We can create FX Image object by using
byte [] bytes = ------; //valid image in bytes
javafx.scene.image.Image image = new Image(new ByteArrayInputStream(bytes));
And this can be set to an ImageView.
I need the opposite without converting it first to the BufferedImage (SwingFXUtils.fromFXImage(image,null)).
So that I can directly write the bytes to a file.
I've tried the following:
PixelReader pixelReader = image.getPixelReader();
int width = (int)image.getWidth();
int height = (int)image.getHeight();
byte[] buffer = new byte[width * height * 4];
pixelReader.getPixels(
0,
0,
width,
height,
PixelFormat.getByteBgraInstance(),
buffer,
0,
width * 4
);
But the file generated by writing the byte [] buffer is not a valid image.
Any insights on this?
EDIT: The solutions given at How to get byte[] from javafx imageView cannot be applied to my question. As I've already mentioned clearly that I do not want to use converting it to BufferedImage using SwingFXUtils.
Moreover, I want to convert it to the byte array so that it can be written to an image file.
This is way later, but if anybody is wanting to find out, try this:
// Load the Image into a Java FX Image Object //
Image img = new Image(new FileInputStream("SomeImageFile.png") );
// Cache Width and Height to 'int's (because getWidth/getHeight return Double) and getPixels needs 'int's //
int w = (int)img.getWidth();
int h = (int)img.getHeight();
// Create a new Byte Buffer, but we'll use BGRA (1 byte for each channel) //
byte[] buf = new byte[w * h * 4];
/* Since you can get the output in whatever format with a WritablePixelFormat,
we'll use an already created one for ease-of-use. */
img.getPixelReader().getPixels(0, 0, w, h, PixelFormat.getByteBgraInstance(), buf, 0, w * 4);
/* Second last parameter is byte offset you want to start in your buffer,
and the last parameter is stride (in bytes) per line for your buffer. */
Using ByteArrayInputStream to create a JavaFX Image will only work using the original, unmodified image file bytes in the supported formats (bmp, jpg, gif, png).
After using PixelReader to read an Image, the byte array will contain raw image bytes that can only be written back to a WritableImage using the PixelWriter, which is why using ByteArrayInputStream produces an invalid image.
Below is a reproducible example using this image:
// Original image bytes
File file = new File("F:/Downloads/duke.png");
byte[] fileBytes = Files.readAllBytes(file.toPath());
System.out.println(fileBytes.length); // 17776 bytes
InputStream in = new ByteArrayInputStream(fileBytes);
Image image = new Image(in);
ImageView view = new ImageView(image);
VBox pane = new VBox();
pane.getChildren().add(view); // Works
in.close();
// PixelReader generated image bytes
int width = (int) image.getWidth();
int height = (int) image.getHeight();
byte[] pixelBytes = new byte[width * height * 4];
System.out.println(pixelBytes.length); // 367928 bytes
image.getPixelReader().getPixels(0, 0, width, height,
PixelFormat.getByteBgraInstance(),
pixelBytes, 0, width * 4);
Image image2 = new Image(new ByteArrayInputStream(pixelBytes));
ImageView view2 = new ImageView(image2);
pane.getChildren().add(view2); // Won't work
// PixelWriter generated image
WritableImage image3 = new WritableImage(width, height);
image3.getPixelWriter().setPixels(0, 0, width, height,
PixelFormat.getByteBgraInstance(),
pixelBytes, 0, width * 4);
ImageView view3 = new ImageView(image3);
pane.getChildren().add(view3); // Works
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
As a raw image format, the PixelReader image is much larger than the original, so if you are storing these images in a database and are concerned about space then you should try storing the original file bytes instead. Otherwise, the SwingFXUtils class can still be used to convert back to compressed format.
Another issue when writing back PixelReader image bytes is that you must somehow store the width and height, either as separate fields in the database or prepended/appended as extra bytes onto the image byte array.

How can I save a color as a PNG image with a specific hex code and dimensions? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'd like to create a PNG file from a specified hex code, width and height. The PNG file will simply comprise the solid color, with the specified dimensions.
Example inputs include #CCCCCC (hex), 500 (width), 300 (height).
That would yield a PNG file that's simply a gray (#CCCCCC) rectangle, with the dimensions of 500 x 300.
Bitmap b = new Bitmap(16, 16);
using (Graphics g = Graphics.FromImage(b))
g.Clear(Color.Yellow);
The Bitmap object can now be used for any purpose you want. If you want to assign it to say a PictureBox, you can use PictureBox.Image = b;. If you want to save this image to disk, you can use b.Save() function and pass it the file path.
If you have a color code, you can use ColorTranslator class to create a Color object from it. It supports HTML, OLE and Win32 color coding schemes. For example, you can use ColorTranslator.FromHtml("#286ECA") to return a Color object of the equivalent color.
You can use Graphics and Bitmap.
Bitmap bmp = new Bitmap(16, 16);
using (Graphics graphics = Graphics.FromImage(bmp))
{
using (SolidBrush brush = new SolidBrush(Color.Yellow))
{
graphics.FillRectangle(brush, 0, 0, bmp.Width, bmp.Height);
}
}
this.BackgroundImage = bmp;
Creating an image with a specified background color can be done like this:
create a Bitmap of the desired size
create a Graphics object that is using the newly created bitmap in order to draw on it
fill the bitmap with the desired color, for example using the Graphics.FillRectangle method
A possible solution could look like this:
var bitmap = new Bitmap(16, 16);
using (var g = Graphics.FromImage(bitmap))
{
g.FillRectangle(Brushes.Yellow, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
}
bitmap.Save("d:\\yellow.jpg");
// or use the bitmap for further operations
If you want to set the colors from RGB values, then you can use the Color.FromArgb method:
var bitmap = new Bitmap(16, 16);
using (var g = Graphics.FromImage(bitmap))
{
using (var brush = new SolidBrush(Color.FromArgb(255, 255, 0)))
{
g.FillRectangle(brush, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
}
}
bitmap.Save("d:\\yellow.jpg");
// or use the bitmap for further operations
As pointed out by #dotNet you can use the ColorTranslator.FromHtml method to parse the specified color:
var bitmap = new Bitmap(16, 16);
using (var g = Graphics.FromImage(bitmap))
{
var colorCode = "#286ECA";
var color = ColorTranslator.FromHtml(colorCode);
using (var brush = new SolidBrush(color))
{
g.FillRectangle(brush, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
}
}
bitmap.Save("d:\\colors.jpg");
// or use the bitmap for further operations

Drawing on image and saving

I guess I don't really understand how Graphics objects work in Visual C++ 2010 Express.
I am grabbing a frame from a webcam, and drawing a circle on it. It works great on the screen. I simply create a Graphics object, draw the image, and draw the ellipse.
In the pictureBox_paint function, I have
Graphics^ g = e->Graphics; // from the camera
System::Drawing::Rectangle destRect = System::Drawing::Rectangle(0,0,pbCameraMonitor->Size.Width,pbCameraMonitor->Size.Height);
double slitHeightToWidth = 3;
g->DrawImage(this->currentCamImage,destRect);
int circleX, circleY;
circleX = (int) (pbCameraMonitor->Size.Width - radius/slitHeightToWidth)/2;
circleY = (int) (pbCameraMonitor->Size.Height - radius)/2;
g->DrawEllipse(Pens::Red, circleX, circleY, (int) radius/slitHeightToWidth, (int) radius);
So far so good, my ellipse gets drawn on there nicely. The destRect bit makes sure it is scaled to the pictureBox size. I simply invalidate the pictureBox every time the camera reports a new image, and I have video.
Now, on a button click I want to save this image, with the red ellipse on it. However, I don't want the rescaled version shown on the screen, I want the full res version. So, I'll grab another frame into a Bitmap^ called "grabbedFrame" and do this:
String ^photofile = "Image_" + expRecord.timestamp.ToString("s") + ".jpg"; // get a unique filename
photofile = photofile->Replace(':', '_');
Graphics^ g = Graphics::FromImage(grabbedFrame);
g->DrawEllipse(Pens::Red, 20, 20, 20, 20); // circle size fixed just for demo
grabbedFrame->Save(photofile, System::Drawing::Imaging::ImageFormat::Jpeg);
When I do that, I get a save of the image without the red circle.
Does g->DrawEllipse actually modify the Bitmap? Or just contain the Bitmap + instructions to draw? If the latter, how does the pictureBox know the Bitmap has been modified? If the former, why doesn't my save contain the modification?
How can I save the modified Bitmap?
You need to draw the loaded image into a new Bitmap, make your modifications to that bitmap, and then save it.
Something like (pseudo-code'ish):
// create bitmap and get its graphics
Bitmap^ pBmp = gcnew Bitmap(grabbedFrame->Width, grabbedFrame->Height);
Graphics^ g = Graphics::FromImage(pBmp);
// draw grabbed frame into bitmap
g->DrawImage(grabbedFrame, 0, 0, grabbedFrame->Width, grabbedFrame->Height);
// draw other stuff
g->DrawEllipse(Pens::Red, 20, 20, 20, 20);
// save the result
pBmp->Save(photofile, System::Drawing::Imaging::ImageFormat::Jpeg);

Stencil testing in XNA 4

I was able to do this in XNA 3.1, however I see that we now use state objects in XNA 4, which is certainly an improvement, although I can't accomplish what I want so far :)
I am trying to:
Clear the stencil buffer to 0.
Draw a texture to the stencil buffer, setting the stencil buffer to 1 where the texture is drawn.
Draw another texture that will only appear where the stencil buffer is not 1.
Here is what I have so far, which appears to have no effect on the drawing of texture 2:
BlendState blend = new BlendState();
blend.ColorWriteChannels = ColorWriteChannels.None;
_preSparkStencil = new DepthStencilState();
_preSparkStencil.StencilEnable = true;
_preSparkStencil.StencilFunction = CompareFunction.Always;
_preSparkStencil.ReferenceStencil = 1;
_preSparkStencil.DepthBufferEnable = true;
_sparkStencil = new DepthStencilState();
_sparkStencil.StencilEnable = true;
_sparkStencil.StencilFunction = CompareFunction.NotEqual;
_sparkStencil.ReferenceStencil = 1;
_sparkStencil.DepthBufferEnable = true;
gd.DepthStencilState = _preSparkStencil;
gd.Clear(ClearOptions.Stencil, Color.Black, 0, 0);
sb.Begin(SpriteSortMode.Deferred, blend);
DrawTexture1();
sb.End();
gd.DepthStencilState = _sparkStencil;
sb.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
DrawTexture2();
sb.End();
gd.DepthStencilState = old;
The problem was that the RenderState needs to be passed into SpriteBatch, or else the SpriteBatch will use it's own RenderState.
sb.Begin(SpriteSortMode.Deferred, BlendState.Opaque,
SamplerState.LinearWrap, _preSparkStencil,
RasterizerState.CullCounterClockwise, CLM.AlphaClip);

Why are transparent pixels showing up black in my image?

I am saving an image bytes array as a thumbnail. The problem is that the transparent background color is black in my image.
Below is my code:
MemoryStream memoryStream = new MemoryStream(pbytImageByteArray);
System.Drawing.Image imgImageSource = System.Drawing.Image.FromStream(memoryStream);
double dblOrgnWidth = imgImageSource.Width;
double dblOrgnHeight = imgImageSource.Height;
double dblRatio = (dblOrgnWidth / dblOrgnHeight) * 100;
double dblScaledWidth = pintWidth;
double dblScaledHeight = 0;
dblScaledHeight = (dblScaledWidth / dblRatio) * 100;
System.Drawing.Bitmap bitmapImage = new System.Drawing.Bitmap(System.Convert.ToInt32(dblScaledWidth), System.Convert.ToInt32(dblScaledHeight));
bitmapImage.SetResolution(imgImageSource.HorizontalResolution, imgImageSource.VerticalResolution);
System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmapImage);
graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
ImageAttributes imageAttributes = new ImageAttributes();
graphics.DrawImage(imgImageSource, new System.Drawing.Rectangle(0, 0, System.Convert.ToInt32(dblScaledWidth), System.Convert.ToInt32(dblScaledHeight)), 0, 0, System.Convert.ToInt32(dblOrgnWidth), System.Convert.ToInt32(dblOrgnHeight), System.Drawing.GraphicsUnit.Pixel);
MemoryStream outputMemoryStream = new MemoryStream();
bitmapImage.Save(outputMemoryStream, System.Drawing.Imaging.ImageFormat.Jpeg);
bitmapImage.GetThumbnailImage(System.Convert.ToInt32(dblScaledWidth), System.Convert.ToInt32(dblScaledHeight), null, IntPtr.Zero);
imgImageSource.Dispose();
bitmapImage.Dispose();
graphics.Dispose();
return outputMemoryStream.ToArray();
JPEG doesn't support transparency. Save as a PNG.
Alternatively, if you know the background color that this will be on, you could set the transparent pixels to that color. If you are using semi-transparent pixels, then you would have to blend the pixels with that color.
Here is an article that explains alpha blending:
http://www.c-sharpcorner.com/UploadFile/mahesh/DrawTransparentImageUsingAB10102005010514AM/DrawTransparentImageUsingAB.aspx
If you are interested in a commercial solution for that (Disclaimer: I work for Atalasoft), DotImage Photo has a class, FlattenAlphaCommand, that can do this in a couple of lines of code.

Resources