I have created BitMapSource from a list of RGBA pixels:
BitmapSource bmp = BitmapSource.Create(imageStrideInPixels, height, 96, 96, PixelFormats.Bgra32, null, imageData, imageStrideInPixels * pixelWidth);
I then create an image from the BitMapSource:
// create image and set image as source
Image BmpImg = new Image();
BmpImg.SetValue(Canvas.ZIndexProperty, 0);
BmpImg.Width = imageScaleWidth;
BmpImg.Height = imageScaleHeight;
BmpImg.Source = bmp;
I then add the Image to the Canvas:
mycanvas.Width = imageScaleWidth;
mycanvas.Height = imageScaleHeight;
mycanvas.Children.Clear();
mycanvas.Children.Add(BmpImg);
Canvas.SetLeft(BmpImg, 0); // to set position (x,y)
Canvas.SetTop(BmpImg, 0);
The problem is that it is not getting scaled to imageScaleWidth and imageScaleHeight, and it is being displayed half way down the canvas.
Note, I was able to do this in Java SWT by:
imageData = imageData.scaledTo(imageScaleWidth, imageScaleHeight);
gc.drawImage(imageData, 0, 0);
You can scale your image using a ScaleTransform:
// scale the original bitmap source
var transformedBitmap = new TransformedBitmap(
bmp,
new ScaleTransform(
imageScaleWidth / (double) bmp.PixelWidth,
imageScaleHeight / (double) bmp.PixelHeight));
// create image and set image as source
Image bmpImg = new Image();
bmpImg.SetValue(Canvas.ZIndexProperty, 0);
bmpImg.Source = transformedBitmap;
mycanvas.Width = imageScaleWidth;
mycanvas.Height = imageScaleHeight;
mycanvas.Children.Clear();
mycanvas.Children.Add(bmpImg);
Note that your image will be positioned at offset 0, 0 by default.
Instead of this
mycanvas.Children.Add(BmpImg);
Try this
mycanvas.Background = new VisualBrush(BmpImg);
This should render properly.
Are you sure the image is half way down the canvas and not the canvas itself is centered in its parent? I tested it and it appears that you can control the canvas position by setting vertical/horizontal alignment on canvas' parent. And also it scales properly when using the code you provided. However I created a BitmapSource in a different way. I used the following code:
PngBitmapDecoder decoder = new PngBitmapDecoder(new Uri(#"..."), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource bmp = decoder.Frames[0];
Related
In JavaFX u can create a new Image from a string(path), how would i go about creating a new Image from an existing javafx.scene.image.image?
as following:
Image image2 = new Image("my/res/flower.png", 100, 150, false, false);
But instead of the path an actual image object.
I want to change the size of the image.
There is typically no need to create a new Image instance in order to perform rescaling. The API allows you to view or draw scaled versions of an existing Image instance. For example, given
Image image = new Image("my/res/flower.png");
you can create an ImageView that displays a scaled version with
ImageView imageView = new ImageView(image);
imageView.setFitWidth(100);
imageView.setFitHeight(150);
or you can draw a scaled version to a canvas with
Canvas canvas = ... ;
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), 0, 0, 100, 150);
A late response, but since I ran into the same issue (I needed an Image to pass to setDragView() ), here is the solution I have implemented:
Image makeThumbnail(Image original) {
ImageView i = new ImageView(original);
i.setFitHeight(64); i.setFitWidth(64);
return i.snapshot(new SnapshotParameters(), new WritableImage(64, 64));
}
I know that my question is a rather basic question, but I tried several days to solve this problem, and can't find the exact answer to my question on Stackoverflow too.
I have a background image, and I want to overlap the foreground image onto it, but only on the regions where my mask has non-zero
values. The code that I wrote is as below. The foreground image appears in
the regions where the mask has non-zero values (in the upper left quarter of the
whole image region), but in the rest of the image, the background does not appear, it just appears 'black'.
I would greatly appreciate if anyone could help
with this problem. A similar code works well for OpenCV for C language.
The background image (background.bmp) and the foreground image (foreground.bmp),
are being read in without problem (this I have verified).
setContentView(R.layout.activity_main);
String pathToBackground
= Environment.getExternalStorageDirectory()+"/background.bmp";
String pathToForeground
= Environment.getExternalStorageDirectory()+"/foreground.bmp";
Mat foreground;
Mat background;
background = imread(pathToBackground); // read in the background image
foreground = imread(pathToForeground); // read in the foreground image
Bitmap back_bitmap = BitmapFactory.decodeFile(path+"/background.bmp");
Utils.bitmapToMat(back_bitmap, background); // convert from bitmap to Mat
Mat mask2 =
new Mat( new Size(foreground.cols(), foreground.rows() ), CvType.CV_8UC1);
mask2.setTo( new Scalar( 0 ) ); // set the mask to all zero
Size sizeMask = mask2.size();
for (int i=0;i<sizeMask.height/2;i++ ) // making the upper left quarter
for (int j=0;j<sizeMask.width/2;j++ ) //of the whole mask image
mask2.put(i, j, 10); // non-zero
foreground.copyTo(background, mask2); // copy the foreground image on to
// the background image where the
// mask2 has non-zero value
// --> not working as expected
Utils.matToBitmap(background, back_bitmap); // convert from Mat to Bitmap
ImageView v = (ImageView)findViewById(R.id.imageView);
v.setImageBitmap(back_bitmap); // only the foreground image appears in the
// upper left region. The remaining region
// is just black.
// The remaining region should show the
// background image.
Thanks to the comments of 'Rick M.', I could solve the problem by the following code (though not very neat). I made an empty bitmap('back_bitmap') instead of
putting an initial image in it. The result is as shown in here.
Before I could not see the background image.
setContentView(R.layout.activity_main);
String pathToBackground =
Environment.getExternalStorageDirectory()+"/background.bmp";
String pathToForeground =
Environment.getExternalStorageDirectory()+"/foreground.bmp";
Mat foreground;
Mat background;
background = imread(pathToBackground);
foreground = imread(pathToForeground);
Bitmap back_bitmap
= Bitmap.createBitmap(foreground.cols(), foreground.rows(),
Bitmap.Config.ARGB_8888); // Make an empty Bitmap
Mat mask2
= new Mat( new Size( foreground.cols(), foreground.rows() ),
CvType.CV_8UC1 );
mask2.setTo( new Scalar( 0 ) );
Size sizeMask = mask2.size();
double[] data;
for (int i=0;i<sizeMask.height;i++ )
for (int j=0;j<sizeMask.width;j++ ) {
data = foreground.get(i, j);
if (data[0] + data[1] + data[2] > 0)
mask2.put(i, j, 10);
}
foreground.copyTo(background, mask2);
Utils.matToBitmap(background, back_bitmap);
ImageView v = (ImageView)findViewById(R.id.imageView);
v.setImageBitmap(back_bitmap);
}
}
I want to strip the alpha channel (transparent background) from PNGs, and then write them as JPEG images. More correctly, I'd like to make the transparent pixels white. I've tried two techniques, both of which fail in different ways:
Approach 1:
BufferedImage rgbCopy = new BufferedImage(inputImage.getWidth(), inputImage.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = rgbCopy.createGraphics();
graphics.drawImage(inputImage, 0, 0, Color.WHITE, null);
graphics.dispose();
return rgbCopy;
Result: image has a pink background.
Approach 2:
final WritableRaster raster = inputImage.getRaster();
final WritableRaster newRaster = raster.createWritableChild(0, 0, inputImage.getWidth(), inputImage.getHeight(), 0, 0, new int[]{0, 1, 2});
ColorModel newCM = new ComponentColorModel(inputImage.getColorModel().getColorSpace(), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
return new BufferedImage(newCM, newRaster, false, null);
Result: Image has a black background.
In both cases, the input image is a PNG and the output image is written as a JPEG as follows: ImageIO.write(bufferedImage, "jpg", buffer). In case it's relevant: this is on Java 8 and I'm using the twelvemonkeys library to resize the image before writing it as a JPEG.
I've experimented with a number of variations of the above code, with no luck. There are a number of previous questions that suggest the above code, but it doesn't seem to be working in this case.
Thanks to Rob's answer, we now know why the colors are messed up.
The problem is twofold:
The default JPEGImageWriter that ImageIO uses to write JPEG, does not write JPEGs with alpha in a way other software understands (this is a known issue).
When passing null as the destination to ResampleOp.filter(src, dest) and the filter method is FILTER_TRIANGLE, a new BufferedImage will be created, with alpha (actually, BufferedImage.TYPE_INT_ARGB).
Stripping out the alpha after resampling will work. However, there is another approach that is likely to be faster and save some memory. That is, instead of passing a null destination, pass a BufferedImage of the appropriate size and type:
public static void main(String[] args) throws IOException {
// Read input
File input = new File(args[0]);
BufferedImage inputImage = ImageIO.read(input);
// Make any transparent parts white
if (inputImage.getTransparency() == Transparency.TRANSLUCENT) {
// NOTE: For BITMASK images, the color model is likely IndexColorModel,
// and this model will contain the "real" color of the transparent parts
// which is likely a better fit than unconditionally setting it to white.
// Fill background with white
Graphics2D graphics = inputImage.createGraphics();
try {
graphics.setComposite(AlphaComposite.DstOver); // Set composite rules to paint "behind"
graphics.setPaint(Color.WHITE);
graphics.fillRect(0, 0, inputImage.getWidth(), inputImage.getHeight());
}
finally {
graphics.dispose();
}
}
// Resample to fixed size
int width = 100;
int height = 100;
BufferedImageOp resampler = new ResampleOp(width, height, ResampleOp.FILTER_TRIANGLE);
// Using explicit destination, resizedImg will be of TYPE_INT_RGB
BufferedImage resizedImg = resampler.filter(inputImage, new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB));
// Write output as JPEG
ImageIO.write(resizedImg, "JPEG", new File(input.getParent(), input.getName().replace('.', '_') + ".jpg"));
}
haraldk was correct, there was another piece of code that was causing the alpha channel issue. The code in approach 1 is correct and works.
However if, after stripping the alpha channel, you resize the image using twelvemonkeys ResampleOp as follows:
BufferedImageOp resampler = new ResampleOp(width, height, ResampleOp.FILTER_TRIANGLE);
BufferedImage resizedImg = resampler.filter(rgbImage, null);
This causes the alpha channel to be pink.
The solution is to resize the image before stripping the alpha channel.
I'm trying to rotate an image using thumbnailator library. It works fine except I don't see any way to set background color of the new image.
Thumbnails.of(image).rotate(45).toByteArray()
If I rotate an image 45 degree it makes corners black. If I need to set some other color, how do I do this?
Example of a rotated image with black background:
You can transform to an "intermediate" image and then apply your background color.
This is mostly untested.
Color newBackgroundColor = java.awt.Color.WHITE;
// apply your transformation, save as new BufferedImage
BufferedImage transImage = Thumbnails.of(image)
.size(100, 60)
.rotate(45)
.outputQuality(0.8D)
.outputFormat("jpeg")
.asBufferedImage();
// Converts image to plain RGB format
BufferedImage newCompleteImage = new BufferedImage(transImage.getWidth(), transImage.getHeight(),
BufferedImage.TYPE_INT_ARGB);
newCompleteImage.createGraphics().drawImage(transImage, 0, 0, newBackgroundColor, null);
// write the transformed image with the desired background color
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(newCompleteImage, "jpeg", baos);
I was wondering, how do I merge/join Android canvases. In the code below I have cnv_left which contains a left part of a button. cnv_center contains the center part. And cnv_text contains text.
What I need is to merge them all in cnv_joined , so that
cnv_left would go first.
then cnv_center.
cnv_text would be in center of cnv_center.
and a flipped cnv_left would be the last.
Here's my code so far:
public void drawButt()
{
float buttonScale = 1.0f; /// general button scale ratio
float buttonScaleCnt = 6.0f; /// button's center part stretch ratio
LinearLayout LinLay = (LinearLayout)findViewById(R.id.linearLayout1);
ImageView iv1 = new ImageView(this);
Bitmap bit_left = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas cnv_left = new Canvas(bit_left);
cnv_left.scale(buttonScale,buttonScale);
SVG svg_left = SVGParser.getSVGFromResource(getResources(), R.raw.btleft);
Picture picture_left = svg_left.getPicture();
picture_left.draw(cnv_left);
Bitmap bit_center = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas cnv_center = new Canvas(bit_center);
cnv_center.scale(buttonScaleCnt, buttonScale);
SVG svg_center = SVGParser.getSVGFromResource(getResources(), R.raw.btcnt);
Picture picture_cnt = svg_center.getPicture();
picture_cnt.draw(cnv_center);
Bitmap bit_text = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas cnv_text = new Canvas(bit_text);
cnv_text.scale(buttonScale, buttonScale);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.WHITE); paint.setTextSize(20);
cnv_text.drawText("R", 2, 30, paint);
Bitmap bit_joined = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
Canvas cnv_joined = new Canvas(bit_joined);
/// somehow need to somehow join the above canvases into this cnv_joined...
iv1.setImageBitmap(bit_joined);
iv1.setPadding(5, 5, 5, 5);
LinLay.addView(iv1);
}
Any ideas? Oh, and one more thing, when I create empty bitmaps for my canvas ( Bitmap.createBitmap(100, 100... ), does it matter what size I give them? If yes, where should I get the correct sizes for them?
Thanks!
Size of Bitmaps matter. If you do Picture.draw to canvas smaller than Picture, image will be cropped to size of bitmap.
Call SVG.getBounds to get bounds and put them in Bitmap constructor.
To join Bitmaps together you have to draw bit_left, bit_center and bit_text on cnv_joined using drawBitmap.
Better way will be to draw SVGs and text directly on cnv_joined.