WPF Image.Source and Transparent Graphics - c#

I'm creating a visual which can have some Images as well. If I use the normal (non-transparent) Png images its working fine (in terms of performance and printing) however as soon as I replace a single transparent png, it becomes very slow and takes more than 3 times of time in printing the visual as well.
I'm using the following code.
var source = new Uri(filePath, UriKind.RelativeOrAbsolute);
BitmapImage imageBitMap =new BitmapImage(source);
var pictureImage = new Image();
pictureImage.Source = imageBitMap;
grid.Children.Add(pictureImage);
I used the ANTS Performance profiler and here are the statistics,
Using 4 graphics (Non-Tranparent) each approximately (50 -100KB) the average time to render them was 10ms for each graphic.
Soon I replace one of them with equivalent Transparent graphic, the average time shoots up and goes up to 34 ms for each graphic.
Any ideas why it takes that long for transparent graphics and how can I reduce it.
I tried to convert the tranparent Pngs into xaml using Adobe Illustrator and InkSpace as well but without success.
The Adobe Illustrator Plug-in, converts the png to 1KB xaml file with having an empty canvas with viewbox in it.
The InkSpace is converting the whole image into base64 string and setting it as source of the Image tag but that is not displaying in the visual at all.

Related

C# Fast load Bitmap into PictureBox

I receve Bitmap image from a camera at 30 fps, and I need to display all images in a pictureBox.
The problem is that the PictureBox is very slow!
I have try to implement a custom PictureBox with DoubleBuffer enabled but the problem is not resolved.
Do you have a custom PictureBox or an user control or a solution that can display the image faster?
Additional information:
The image resolution is 2048x1088 with 256 graylevel (8bit image).
I use AForge.NET for elaborate the images.
Thank you
That image gets expensive to draw when it has to be resized to fit the PB's client area. Which is very likely in your case because your images are pretty large. It uses a high-quality bi-cubic filter to make the resized image look good. That's pretty expensive, albeit that the result is good.
To avoid that expense, resize the image yourself before assigning it to the Image property. Make it just as large as the PB's ClientSize.
That's going to make a big difference in itself. The next thing you can do is to create the scaled bitmap with the 32bppPArgb pixel format. It's the format that's about 10 times faster then any other because it matches the video adapter on most machines so no pixel format conversions are necessary.

overlay images on top of an existing image (web)

My goal is to display a large rectangular image in a section of a webpage that will act as a background for other, smaller images to be laid on top of. The smaller rectangular images will be dynamically selected based upon database entries. I was able to create a java applet that drew the larger base rectangular image and then drew the smaller images over the base image. This worked very well.
I am attempting to recreate the functionality using C# in Microsoft Visual Web Developer 2010. I have found system.drawing functionally that may work, but haven’t found a web based solution yet. Any help would be appreciated.
If I understand correctly, you want to overlay smaller images on top of another image. At the end you'll end up with one image to display. This is easy to do in C#:
string image1 = #"c:\image.jpg";
string image2 = #"c:\image2.jpg";
System.Drawing.Image canvas = Bitmap.FromFile( image1 );
Graphics gra = Graphics.FromImage( canvas );
Bitmap smallImg = new Bitmap(image2);
gra.DrawImage( smallImg, new Point( 70, 70 ) );
canvas.Save( #"c:\newimage.jpg", System.Drawing.Imaging.ImageFormat.Jpeg );
My two cents here... Another thing which helped me on .NET 2.0 and 3.0 was explicitly deleting the Image, Graphics and Bitmap objects after you are done, specially when you would be accessing any of the image sources (image1, image2 and smallImg above) within the same routine.
Deleting these objects will instantly release the file locks. I experienced that the garbage collector wouldn't necessarily clean these up for me at the desired time, even if I made a separate sub-routine for my image manipulation.

Resizing Resulting Camera Stream

I am trying to let a user capture an image and add it onto the screen using an Image. However, I also need to resize this image down to about half size due to memory restrictions (12x 5MP images is never good on a phone...)
I am launching the camera task fine and it calls the Completed event. However, when I try and use DecodeJpeg I get a "The parameter is incorrect." exception.
Here is my code for resizing, where mx and my are int for dimensions. I have verified that there is something in the e.ChosenPhoto with a length of about ~5500:
WriteableBitmap bitmap = PictureDecoder.DecodeJpeg(e.ChosenPhoto, mx, my);
Image img = new Image();
img.Source = bitmap;
The first line is where the app crashes. Any ideas?
EDIT:
This also occurs with the result from the PhotoChooserTask....
Try using the System.Windows.Media.Imaging - Extensions.LoadJpeg method instead of PictureDecoder.DecodeJpeg. Also make sure that the stream is positioned at the beginning of the stream. If you have already used the stream you will need to reset it using:
MyImageStream.Seek(0, System.IO.SeekOrigin.Begin)
I had a lot of problems trying to get access to the original image, especially since BitmapImage automatically resizes images over 2000x2000. If you want an image larger than 2000x2000 you have to have access to the original stream and load it into a WriteableBitmap object
If you want to see some more complex image handling code including detecting resolution from image stream using ExifLib and rotating stream using the WriteableBitmap Extensions check out the BarcodeCaptureResult class for the Silverlight ZXing Library.
UPDATE: Since all you want is to resize an image given the e.ChosenPhoto result I pulled the code from The Silverlight ZXing library. This should work:
WriteableBitmap wbBarcodeImage = new WriteableBitmap(mx, my);
Extensions.LoadJpeg(wbBarcodeImage, e.ChosenPhoto);//Load JPEG from stream into our re-sized writeable bitmap
Note that you will need to use the correct height/width ratio, otherwise you will have a black bar at the bottom or side of the image. You can use ExifLib to detect the original image size and use that to scale (see GetWriteableBitmap method in BarcodeCaptureResult linked above)

Display picture box faster

I am trying to load images quickly into a picturebox and draw on them. I have a .13 second delay between the time I assign a bitmap to the picture box and when it shows up. And whenever I do a picturebox.refresh(), it is the same delay of .13 - .15 seconds before the paint method is called. Is there any way to get rid of this delay?
I am using C# in Visual Studio 2010. I load the images using FreeImage library.
Here is the code in my pictureBox_MouseMove event:
if (IsMouseDown || DrawLine.Checked || IsMovingBox)
{
Tracing.Trace("Update Picture Box");
pictureBox.Refresh();
}
Then I trace out a line when my paint event is called. The delay is between the two trace lines.
If I use a bitonal tiff image at 117kb the delay is .13 seconds. To load this image into memory takes .04 seconds. To replace my picturebox bitmap with this bitmap takes .01 seconds.
If I use a gray scale jpg image at 1125kb the delay is .14 seconds. To load this image into memory takes .26 seconds. To replace my picturebox bitmap with this bitmap takes .03 seconds.
Assuming there are no other delays in your code that would prevent the UI thread from re-entering the message loop so that the OnPaint() method can be called: your Paint event handler gets called after PictureBox has drawn the Image. It isn't yet visible, PB uses double-buffering.
That image gets expensive to draw when it has to be resized to fit the PB's client area. Which is very likely in your case because your images are pretty large. It uses a high-quality bi-cubic filter to make the resized image look good. That's pretty expensive, albeit that the result is good.
To avoid that expense, resize the image yourself before assigning it to the Image property. Make it just as large as the PB's ClientSize.
That's going to make a big difference in itself. The next thing you can do is to create the scaled bitmap with the 32bppPArgb pixel format. It's the format that's about 10 times faster then any other because it matches the video adapter on most machines so no pixel format conversions are necessary.
Some code:
private void loadImage(string path) {
using (var srce = new Bitmap(path)) {
var dest = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (var gr = Graphics.FromImage(dest)) {
gr.DrawImage(srce, new Rectangle(Point.Empty, dest.Size));
}
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
pictureBox1.Image = dest;
}
}
You'll probably want to tinker with this so the image preserves its aspect ratio. Try it first as-is to make sure you do get the perf improvement.

How to serve high-resolution imagery in a low-resolution form using C#

Trying to use 300dpi tif images for display on the web. At the moment, when the user uploads an image, I am dynamically creating a thumbnail. If a page is created referencing the high-res image with a width of 500x500px, can I use the same functionality to convert to a gif/jpg on the fly. What is the impending resolution of the jpg that would be created?
EDIT:
To further explain the usage, the user uploads 300dpi images which are approx 3000x3000 pixels. The user is using these images to create a catalog page which will be used for pdf printing. When they are creating the page, we only need 72dpi images to display to the screen, but for print, need the 300dpi images. Obviously they do not want to add a 3000x3000px image to the page, so it needs to be resized to the correct viewing area, e.g. 500x500px etc.
This boils down to a simple image resize. The discussion of DPIs is just ancillary data to calculate the scale factor.
As #Guffa said, you should do this at the time of the upload so that you can just serve static images in your viewer.
This will be a load on the server:
Load the full image. This will be about 27 MB of memory for your 3000x3000 images.
Resize. Lot's of math done lazily (still CPU intensive).
Compress. More CPU + Cost of writing to your drive.
Since you are already taking the time to generate a thumbnail, you can amortize that cost and this cost by not having to repeat Step 1 above (see the code).
After an image is uplaoded, I would recommend spinning off a thread to do this work. It's a load on the web server for sure, but you're only other option is to devote a second machine to performing the work. It will have to be done eventually.
Here is some code to do the job. The important lines are these:
OutputAsJpeg(Resize(big, 300.0, 72.0), new FileStream("ScreenView.jpg"));
OutputAsJpeg(Resize(big, bigSize, 64.0), new FileStream("Thumbnail.jpg"));
We can resize the big image however we need. In the first line we just scale it down by a fixed scale (72.0 / 300.0). On the second line, we force the image to have a final max dimension of 64 (scale factor = 64.0 / 3000.0).
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;
BitmapSource Resize(BitmapSource original,
double originalScale,
double newScale) {
double s = newScale / originalScale;
return new TransformedBitmap(original, new ScaleTransform(s, s));
}
void OutputAsJpeg(BitmapSource src, Stream out) {
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(src));
encoder.Save(out);
}
// Load up your bitmap from the file system or whatever,
// then dump it out to a smaller version and a thumbnail.
// Assumes thumbnails have a max dimension of 64
BitmapSource big = new BitmapImage(new Uri("BigPage0.png",
UriKind. RelativeOrAbsolute));
double bigSize = Math.Max(big.PixelWidth, big.PixelHeight);
OutputAsJpeg(Resize(big, 300.0, 72.0), new FileStream("ScreenView.jpg"));
OutputAsJpeg(Resize(big, bigSize, 64.0), new FileStream("Thumbnail.jpg"));
If I understand what you want - you're trying to make a gif or jpg thumbnail of a very high resolution tif, for web display - if not, I apologize in advance....
If you want the thumbnail to be 500x500px, that is the resolution of the jpg/gif you'll want to create - 500x500, or at least 500x<500 or <500x500 (to fit in the box, unless you want distorted images).
For display on the web, the DPI does not matter. Just use the pixel resolution you wish directly.
Technically the JPG/GIF is created at 72-DPI by the Image classes in .NET. But the DPI really doesn't have any meaning to the browser - it just uses the dimensions 500x500.
When displaying an image on a web, the dpi (or more correctly ppi) setting is irrelevant. It's only the size in pixels that is relevant.
You can convert an image on the fly, but it is very work intensive for the server to do that every time the image is displayed. You should create the sizes that you need when the user uploads the image.

Categories

Resources