.net Drawing.Graphics.FromImage() returns blank black image - asp.net

I'm trying to rescale uploaded jpeg in asp.net
So I go:
Image original = Image.FromStream(myPostedFile.InputStream);
int w=original.Width, h=original.Height;
using(Graphics g = Graphics.FromImage(original))
{
g.ScaleTransform(0.5f, 0.5f); ... // e.g.
using (Bitmap done = new Bitmap(w, h, g))
{
done.Save( Server.MapPath(saveas), ImageFormat.Jpeg );
//saves blank black, though with correct width and height
}
}
this saves a virgin black jpeg whatever file i give it.
Though if i take input image stream immediately into done bitmap, it does recompress and save it fine, like:
Image original = Image.FromStream(myPostedFile.InputStream);
using (Bitmap done = new Bitmap(original))
{
done.Save( Server.MapPath(saveas), ImageFormat.Jpeg );
}
Do i have to make some magic with g?
upd:
i tried:
Image original = Image.FromStream(fstream);
int w=original.Width, h=original.Height;
using(Bitmap b = new Bitmap(original)) //also tried new Bitmap(w,h)
using (Graphics g = Graphics.FromImage(b))
{
g.DrawImage(original, 0, 0, w, h); //also tried g.DrawImage(b, 0, 0, w, h)
using (Bitmap done = new Bitmap(w, h, g))
{
done.Save( Server.MapPath(saveas), ImageFormat.Jpeg );
}
}
same story - pure black of correct dimensions

Since you didn't fill the area with background of image you're reading from inputStream,you can only get a blank image that way.
Instead of using scaling the image,you can use Fill background into a resized area.
Check this out:
Image img = Image.FromFile(Server.MapPath("a.png"));
int w = img.Width;
int h = img.Height;
//Create an empty bitmap with scaled size,here half
Bitmap bmp = new Bitmap(w / 2, h / 2);
//Create graphics object to draw
Graphics g = Graphics.FromImage(bmp);
//You can also use SmoothingMode,CompositingMode and CompositingQuality
//of Graphics object to preserve saving options for new image.
//Create drawing area with a rectangle
Rectangle drect = new Rectangle(0, 0, bmp.Width, bmp.Height);
//Draw image into your rectangle area
g.DrawImage(img, drect);
//Save your new image
bmp.Save(Server.MapPath("a2.jpg"), ImageFormat.Jpeg);
Hope this helps
Myra

Try this:
- get the Image from your stream
- create a new Bitmap of the correct size
- get the Graphics object from the new bitmap, not the original one
- call g.DrawImage(original, 0, 0, done.Width, done.Height)
Edit:
The problem is this section:
using (Bitmap done = new Bitmap(w, h, g))
{
done.Save( Server.MapPath(saveas), ImageFormat.Jpeg );
}
You're creating a black bitmap, with the resolution specified by g. You're not actually creating a bitmap with any image data coming from g. In fact, I don't think the Graphics object actually stores image data that you can really pass around, it just allows you to manipulate some object that stores the image data.
Try replacing that with b.Save(...)

Related

JavaFx ImageViewer from unsigned short array

I want to display an image received in a short[] of pixels from a server.
The server(C++) writes the image as an unsigned short[] of pixels (12 bit depth).
My java application gets the image by a CORBA call to this server.
Since java does not have ushort, the pixels are stored as (signed) short[].
This is the code I'm using to obtain a BufferedImage from the array:
private WritableImage loadImage(short[] pixels, int width, int height) {
int[] intPixels = new int[pixels.length];
for (int i = 0; i < pixels.length; i++) {
intPixels[i] = (int) pixels[i];
}
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
WritableRaster raster = (WritableRaster) image.getData();
raster.setPixels(0, 0, width, height, intPixels);
return SwingFXUtils.toFXImage(image, null);
}
And later:
WritableImage orgImage = convertShortArrayToImage2(image.data, image.size_x, image.size_y);
//load it into the widget
Platform.runLater(() -> {
imgViewer.setImage(orgImage);
});
I've checked that width=1280 and height=1024 and the pixels array is 1280x1024, that matches with the raster height and width.
However I'm getting an array out of bounds error in the line:
raster.setPixels(0, 0, width, height, intPixels);
I have try with ALL ImageTypes , and all of them produce the same error except for:
TYPE_USHORT_GRAY: Which I thought it would be the one, but shows an all-black image
TYPE_BYTE_GRAY: which show the image in negative(!) and with a lot of grain(?)
TYPE_BYTE_INDEXED: which likes the above what colorized in a funny way
I also have tried shifting bits when converting from shot to int, without any difference:
intPixels[i] = (int) pixels[i] & 0xffff;
So..I'm quite frustrated after looking for days a solution in the internet. Any help is very welcome
Edit. The following is an example of the images received, converted to jpg on the server side. Not sure if it is useful since I think it is made from has pixel rescaling (sqrt) :
Well, finally I solved it.
Probably not the best solution but it works and could help someone in ether....
Being the image grayscale 12 bit depth, I used BufferedImage of type TYPE_BYTE_GRAY, but I had to downsample to 8 bit scaling the array of pixels. from 0-4095 to 0-255.
I had an issue establishing the higher and lower limits of the scale. I tested with avg of the n higher/lower limits, which worked reasonably well, until someone sent me a link to a java program translating the zscale algorithm (used in DS9 tool for example) for getting the limits of the range of greyscale vlues to be displayed:
find it here
from that point I modified the previous code and it worked like a charm:
//https://github.com/Caltech-IPAC/firefly/blob/dev/src/firefly/java/edu/caltech/ipac/visualize/plot/Zscale.java
Zscale.ZscaleRetval retval = Zscale.cdl_zscale(pixels, width, height,
bitsVal, contrastVal, opt_sizeVal, len_stdlineVal, blankValueVal);
double Z1 = retval.getZ1();
double Z2 = retval.getZ2();
try {
int[] ints = new int[pixels.length];
for (int i = 0; i < pixels.length; i++) {
if (pixels[i] < Z1) {
pixels[i] = (short) Z1;
} else if (pixels[i] > Z2) {
pixels[i] = (short) Z2;
}
ints[i] = ((int) ((pixels[i] - Z1) * 255 / (Z2 - Z1)));
}
BufferedImage bImg
= new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
bImg.getRaster().setPixels(0, 0, width, height, ints);
return SwingFXUtils.toFXImage(bImg, null);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return null;

Asp.net image resizing quality

I have this code that I use to resize and save a file that is posted by the user.
The issue is that when I rezise to a 480px width the image looses lots of quality and the size in kb is still pretty big.
For instance, when I resize the same image to 480px "by hand" using a software like Paint, the quality is still as good as the original (from what my eye can tell) and the size in kb is a lot smaller than resizing using the GetThumbNailImage method.
Mdn says "If you request a large thumbnail image (for example, 300 x 300) from an Image that has an embedded thumbnail, there could be a noticeable loss of quality in the thumbnail image. It might be better to scale the main image (instead of scaling the embedded thumbnail) by calling the DrawImage method.", but that seems to be for Windows forms and I need for a web app.
What code should I use to do this then?
System.IO.Stream st = FileUploadPost.PostedFile.InputStream;
myImage = System.Drawing.Image.FromStream(st);
thumb = myImage.GetThumbnailImage(newWidth, newHeight, null, System.IntPtr.Zero);
thumb.Save(myPath);
Here is code that has worked for me. You can set the new bitmap resolution:
using System.Drawing;
Bitmap img = (Bitmap)Bitmap.FromStream(FileUploadPost.PostedFile.InputStream);
Bitmap newImg = new Bitmap(maxWidth, maxHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
newImg.SetResolution(72, 72);
Graphics newGraphic = Graphics.FromImage(newImg);
newGraphic.Clear(Color.Transparent);
newGraphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
newGraphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
newGraphic.DrawImage(img, 0, 0, maxWidth, maxHeight);
System.Drawing.Imaging.ImageFormat format = default(System.Drawing.Imaging.ImageFormat);
string ext = Path.GetExtension(FileUploadPost.PostedFile.FileName);
switch (ext.ToLower())
{
case ".gif":
format = System.Drawing.Imaging.ImageFormat.Gif;
break;
case ".png":
format = System.Drawing.Imaging.ImageFormat.Png;
break;
default:
format = System.Drawing.Imaging.ImageFormat.Jpeg;
break;
}
newImg.Save(myPath, format);
You can wrap it in a void function on a global class:
public static void UploadImage(HttpPostedFileBase file, int maxWidth, int maxHeight)
{
//paste all the above code in here and replace FileUploadPost.PostedFile with file
}
Then you can call it from anywhere in your project:
ClassName.UploadImage(FileUploadPost.PostedFile, 300, 300);
Does this answer sufficiently?
Resizing an image in asp.net without losing the image quality
This is an issue that comes up fairly frequently.
Try this
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
public static System.Drawing.Image ResizeImage( System.Drawing.Image image, int percent ) {
// percent is the actual integer percent of the original size
System.Drawing.Bitmap imgThumb = new System.Drawing.Bitmap( image.Width * percent / 100, image.Height * percent / 100 );
Rectangle sourceRect = new Rectangle( 0, 0, image.Width, image.Height );
Rectangle destRect = new Rectangle( 0, 0, imgThumb.Width, imgThumb.Height );
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage( imgThumb );
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage( image, destRect, sourceRect, GraphicsUnit.Pixel );
return ( imgThumb );
}

GDI+ DrawImage function

There is something I am missing. Say I have the following code:
private Bitmap source = new Bitmap (some_stream);
Bitmap bmp = new Bitmap(100,100);
Rectangle newRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
Rectangle toZoom= new Rectangle(0, 0, 10, 10);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(source, newRect, toZoom, GraphicsUnit.Pixel);
My goal is to zoom-in the 10x10 pixels on the top left corner of the source picture. After I created the graphics object g and called DrawImage: the requested rectangle (toZoom) will be copied to bmp, or will it be displayed on the screen? I am a bit confused, can somebody please clarify?
You code will only give you an in-memory bitmap (which won't automatically be displayed to the screen). A simple way to display this would be to put a 100 x 100 PictureBox on your form, and set its Image property like this (using the Bitmap from your code above):
pictureBox1.Image = bmp;
Also, you'll want some using blocks in your code:
using (private Bitmap source = new Bitmap (some_stream))
{
Bitmap bmp = new Bitmap(100,100);
Rectangle newRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
Rectangle toZoom= new Rectangle(0, 0, 10, 10);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawImage(source, newRect, toZoom, GraphicsUnit.Pixel);
}
pictureBox1.Image = bmp;
}
Note that there is no using block with bmp - this is because you're setting it as the PictureBox's Image property. The using block automatically calls an object's Dispose method at the end of the block's scope, which you don't want to do since it will still be in use.
it will be copied and not displayed.

to crop a image by selecting part of imageusing ActionScript3.0 and Flex3.0

To crop the image into a selected size by drawing rectangle over it. It should be done in ActionScript 3.0 and Flex 3.0
warm rgds,
You can use BitmapData.copyPixels() for this.
//create a rectangle
var cropRect:Rectangle = new Rectangle(left, top, width, height);
//create new bitmap data - because BitmapData's width/height are read only
var bmpData:BitmapData = new BitmapData(cropRect.width, cropRect.height, true);
bmpData.copyPixels(image.bitmapData, cropRect, new Point(0, 0));
//assign the cropped bitmap data to the image.
image.bitmapData = bmpData;
copyPixels() method
public function copyPixels(sourceBitmapData:BitmapData, sourceRect:Rectangle,
destPoint:Point, alphaBitmapData:BitmapData = null, alphaPoint:Point = null,
mergeAlpha:Boolean = false):void
Provides a fast routine to perform pixel manipulation between images with no stretching, rotation, or color effects. This method copies a rectangular area of a source image to a rectangular area of the same size at the destination point of the destination BitmapData object.

How to get RGB values of a pixel in JavaFX

I am getting started with JavaFX and basically what I am trying to implement is a Color Picker.
At first, I thought of having a rectangle with a LinearGradient that goes through all primary/secondary colors.
Looks like what I want, but the problem is that I can not get the RGB values at a given coordinate(x,y) in this Node.
I know you can do it through the fill property of any Shape IF it is a Color.
But Is there anyway to get the RGB values of anything inside a LinearGradient/Paint ?
Does this ColorPicker JavaFX example help?
[...]
function colorAtLocation(x:Integer, y:Integer) : Color {
var bimg = iv.image.bufferedImage;
if (x < 0 or x >= bimg.getWidth() or y < 0 or y >= bimg.getHeight()) {
return null;
}
var rgb = bimg.getRGB(x, y);
var r = Bits.bitAnd(Bits.shiftRight(rgb, 16), 0xff);
var g = Bits.bitAnd(Bits.shiftRight(rgb, 8), 0xff);
var b = Bits.bitAnd(Bits.shiftRight(rgb, 0), 0xff);
Color.rgb(r, g, b)
}
function updateSelectedColor(e:MouseEvent) {
var rgb = colorAtLocation(e.x, e.y);
if (rgb != null) {
picker.selectedColor = rgb;
}
}
[...]
The ColorPicker JavaFX example starts with a png image that is loaded to an image that then populates the ImageView.
The question starts with a JavaFX Rectangle containing LinearGradient.
To get the rectangle contents into a buffered image, one can use the java.awt.Robot:
var rectangle = new java.awt.Rectangle(x,y,width,height);
var robot = new java.awt.Robot();
var bufferedImage = robot.createScreenCapture(rectangle);
where rectangle would be describe the coordinates of the JavaFX Rectangle containing the bits of interest.
The robot.createScreenCapture call has the gotcha that to do the screen capture, the screen has to be visible. There should be a better of way to populate the buffered image but I've not yet encountered it.

Resources