Convert JavaFX Image object to byte array - image

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.

Related

JavaFx Displaying Images from pixel array

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.

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

How to crop an Image using CvRect in Open CV.

I want to crop an image of 1176*640 to save the ROI of 1176*400 size. I am using the following snippet to acheive bit I am still getting the original image as output.
IplImage *CMyFunction::ROI(IplImage *pImage, CvRect ROI)
{
IplImage *mROI = cvCreateImage(cvGetSize(*pImage), IPL_DEPTH_8U, 1);
cvSetImageROI(pImage, rect_ROI);
cvCopy(pImage, mROI);
cvResetImageROI(pImage);
return mROI;
}
For cvCopy() the source and destination should be same size and type, that is the parameter like width, height, depth, and number of channel should be equal for both image. In your case you can change your code either like
IplImage *mROI = cvCreateImage(cvGetSize(pImage), pImage->depth, pImage->nChannels); //create dest with same size as source
cvSetImageROI(pImage, rect_ROI); //Set roi on source
cvSetImageROI(mROI, rect_ROI); //set roi on dest
cvCopy(pImage, mROI);
cvResetImageROI(pImage);
cvResetImageROI(mROI);
or
IplImage *mROI = cvCreateImage(cvSize(rect_ROI.width,rect_ROI.height), pImage->depth, pImage->nChannels); // create an image of size as rect
cvSetImageROI(pImage, rect_ROI); //set roi on source
cvCopy(pImage, mROI);
cvResetImageROI(pImage);
I understood that the pointer when leaves the function is no longer stable and declared a new IplImage* outside of the function and pass it as a parameter which proved to be efficient.
IplImage *CMyFunction::ROI(IplImage *pImage, CvRect ROI, IplImage* FinalImage)

opencv: change image size without effecting content size

I am getting image containing character after applying my image process. All these images (having character as content) have different size. I want to resize all images in same size without effecting it's content size. see below image:
http://techsture.com/img.jpg
I have tried some function to merge my source image with other white image but it needs both source images with same size. I need common size of images for further process.
Please guide me how can I convert my images to common size ??
Thank you
I would make a new image with the destination size, set a ROI in this new image to where you want the source image to show. Then use cvResize.
It should look something like:
int newWidth = 100;
int newHeight = 100;
CvRect rect;
IplImage* source = cvLoadImage("c:/myimage");
IplImage* dest = cvCreateImage(cvSize(newWidth,newHeight),source->depth,source->nChannels);
rect.x = newWidth/2 - source->width/2;
rect.y = newHeight/2 - source->height/2;
rect.width = source->width;
rect.height = source->height;
cvSetImageROI(dest,rect);
cvResize(source,dest);
cvResetImageROI(dest);

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