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.
Related
I want to compare two images and then generate and save an image that will show all the differences that has been found,
for example:
I am using ImageMagick: https://magick.codeplex.com/
But they don't have full documentation for C#.
I found only: http://www.imagemagick.org/Usage/compare/
This code for example show value from 0-1 that represent how similar the pictures are:
MagickImage img1 = new MagickImage(#"C:\test\Image1.jpg");
MagickImage img2 = new MagickImage(#"C:\test\Image2.jpg");
double diff = img1.Compare(img2,new ErrorMetric());
But how can I compare the images using ImageMagick and then save the result as shown in the example above and in their website?
Update:
With the help of dlemstra I wrote the following code and I generate images that suppose to show the difference as in the example above.
MagickImage img1 = new MagickImage(#"C:\test\Image1.jpg");
MagickImage img2 = new MagickImage(#"C:\test\Image2.jpg");
MagickImage img3 = new MagickImage(#"C:\test\Image3.jpg");
MagickImage img4 = new MagickImage(#"C:\test\DiffImage.jpg");
MagickImage img5 = new MagickImage(#"C:\test\DiffImage.jpg");
var imgDiff = new MagickImage();
img1.Compare(img2, new ErrorMetric(), imgDiff);
imgDiff.Write(#"C:\test\Diff4.jpg");
img1.Compare(img3, new ErrorMetric(), imgDiff);
imgDiff.Write(#"C:\test\Diff5.jpg");
img1.Compare(img4, new ErrorMetric(), imgDiff);
imgDiff.Write(#"C:\test\Diff6.jpg");
img5.Compare(img4, new ErrorMetric(), imgDiff);
imgDiff.Write(#"C:\test\Diff7.jpg");
The Strange results are: When I compare the following two images with the marked only difference:
This is the result that I get (And not as the example above from "imageMagick"
You will need to use one of the other overloads of the Compare method for this. The example below demonstrates how to do this:
using (var img1 = new MagickImage(#"C:\test\Image1.jpg"))
{
using (var img2 = new MagickImage(#"C:\test\Image2.jpg"))
{
using (var imgDiff = new MagickImage())
{
double diff = img1.Compare(img2, new ErrorMetric(), imgDiff);
imgDiff.Write(#"C:\test\Diff-Image1-Image2.jpg");
}
}
}
But when you are working with jpeg images (they are lossy) you probably also want to set the ColorFuzz on the first image:
img1.ColorFuzz = new Percentage(5); // adjust this value for your situation
This will make it so that pixels that are almost the same will also match.
Lessons Learned:
Wanted to add some important notes so others hopefully avoid the pitfalls which I ran into when testing out ImageMagick (or any compare tool) for the first time.
Beware of editing in Windows Paint in general.
Don’t edit a *.png with a transparent background in Windows paint and expect a good compare. Windows Paint doesn’t handle transparent background and the png you edited in Paint will now have a white background. The Image will look exactly the same to the naked eye but the image comparers know better.
If you have SnagIt, this is a better tool for making edits to an image when you want to put a image compare tool to the test.
Conclusion:
The code written by #dlemstra does work as expected. Just make sure that when you are testing out the first time that the second image (which you modified) didn’t get unintentionally modified by the image editor that you use. This is a general warning for when you are testing out any image compare tool for the first time to see if you want to use it or not.
Examples:
Example 1: Transparent png + Windows Paint
Downloading a transparent image, making and edit to it in Paint which unintentionally also changes background to white instead of transparent.
Just by opening, then saving the second image in Paint without making any edits to the image will cause the diff to look like this:
I couldn’t figure out what was going on until I compared with Beyond Compare:
Example 2: Complex *.jpg + Windows Paint
Windows Paint was also not good at keeping complex images identical between saves:
The big red areas were changes I had made, but the thin outlines of the roses were changes that Windows Paint made to the picture
Even when I made no changes at all and just open, saved and closed the second image in Paint (and the original image was an image which had also been saved in Paint), Paint still made undesired edits to the picture (dark red dots in image):
I then had an original image which had been saved in Paint and copied this image, opened the second image in snagIt, saved the second image in snagit, and then closed the image and compared the two images (which should have been identical). However, it seemed that snagIt made it’s own modifications to the original ‘Paint saved’ image:
Lastly, I copied the ‘Snagit saved’ image, opened this second image also in SnagIt, made an edit to the second image, saved the image in SnagIt and then closed the image. SnagIt did not make any modifications to this image and the compare showed exactly what I expected:
Lastly:
Most information you find about ImageMagick pertains to using it via the command line. You can add the Magick.Net nuget to your C# project in Visual Studio by installing it via the NuGet Package Manager
This is a C# winforms question.
The process I am trying to achieve is the following:
Using AxAcroPDFLib I'm loading a pdf file to the form
I want the user to be able to specify a square on that PDF and create a bmp from it
That bmp will then be loaded to a OCR to become text
What is my issue:
Step 1 and 3 are easy to do, the problem is how to allow the user to draw a square on top of the AxAcroPDFLib for a screenshot.
I already got different ways to draw squares on native winform components, but AxAcroPDFLib does not support mouse down, up, move, etc and paint events.
There is the option to convert the PDF to bitmap and display it on a picturebox and deal with events for drawing the square. Problem with that approach is that my PDF's are usually more than two pages, and I would like to avoid the conversion pdf to bmp due to changes to image quality that will impact on OCR.
I came to think that maybe something that works as the windows snippingtool would do the the job. My application would get the screenshot, temporarily save the image on disk (must be a file for OCR), I would then pass it to the OCR and done. Hard part, I could not think on how to take the screenshot of part of the PDF.
Do anyone here have any suggestion to different components or workarounds to deal with the requirement above? I am using Adobe just because it is simple, but maybe there are other components better suited to handle my requirements? I googled but haven't found any free ones, trying to avoid paid options.
Thanks
At some point in this process, the PDF is going to have to be rasterized in order to be passed to the OCR, so I don't totally understand your objection to converting it to a bitmap. If you're okay with Snipping Tool's behavior, then you must be OK with the quality of the PDF control's PDF->screen rasterization. If that resolution is acceptable, why not just capture the control's content to a Bitmap and let the user draw the selection marquee over that Bitmap?
Here is code I'm using to capture a control's contents to a Bitmap in Windows Forms. One caveat is that this is really a screen capture, so any windows or controls that overlap the control's visible area will be captured in the image.
using (Bitmap b = new Bitmap(width, height))
{
using (Graphics g = Graphics.FromImage(b))
{
Point p1 = myControl.PointToScreen(new Point(0, 0));
g.CopyFromScreen(p1.X, p1.Y, 0, 0, size);
}
// do stuff here with your Bitmap
}
Alright guys last little bit of this project I'll ask for help on I promise.
So I go to load the images, works fine however I notice upon loading that the dimensions of the image have been scaled down in the y to 300 (all are a constant value of 433) and up or down from their original width to 600.
I'm using the following method to load them
foreach (string file in Directory.EnumerateFiles(imagePath, "*.JPG"))
{
Image contents = Image.FromFile(file);
treesImage[count] = contents;
count++;
}
and this is the resulting image when I have it loaded.
http://i.stack.imgur.com/Q40kK.png
As you can see the image below the red rectangle is quite small
Any help would be appreciated. If you require any more information please post below and I'll make sure to edit the original question with the relevant information as soon as humanly possible.
EDIT: I am using a simple windows form application and not another graphical framework for my own reasons.
Thanks in advance :)
I'll assume you are using a PictureBox control to display the image.
When someone chooses a tree from your map, you obviously set the PictureBox Image property to the image object referenced by the index in the array. Use the Image object to set the ClientSize of the PictureBox control.
...
Image img = treesImage[idx];
MyPictureBox.SizeMode = PictureBoxSizeMode.Normal;
MyPictureBox.ClientSize = new Size(img.Width,img.Height);
MyPictureBox.Image = img;
...
Alternately you can define one size for your PictureBox and force all the images to be scaled to that size by setting the control SizeMode property to StretchImage declaratively.
I would recommend that you create a simple class (MyImageInfo for example) that would store the Path, Width, and Height of the images found in your first function into a list and then just as before when a user clicks to view an image you set the width and height of the PictureBox and then call the LoadAsync(path) method to get the image. then you aren't storing all images in memory at once, just as you need them since it doesn't look like this requires a lot of quick jumping from image to image.
I would like to know how I can create one image from many. I would like to create a tile in my windows phone application like in this image (specifically, the People tile):
(source: addictivetips.com)
I have nine pictures, and I would create an image, that I will add like tile to background. Does anybody know how can I create an image that looks like the one in that picture?
I have very little experience in this space, but have you considered creating a control that simply displays up to 9 pictures side by side in a grid like that? You then can bind each image independently & change them out however you want. This article touches on how to bind phontos in WP7 nicely:
http://msdn.microsoft.com/en-us/library/hh286418(v=vs.92).aspx
If you're talking about assembling an actual graphic image like a jpeg or bitmap, you'll need to look at the Image Class, Bitmap Class, and Graphics Class. Essentially you'll need to implement the following steps:
Load the relevant images with From method in Image, typically Image.FromFile.
Determine how many rows and columns you'll be using.
Calculate the total width and height for your layout using the widths and heights of the loaded images with appropriate padding added.
Create a new Bitmap of the appropriate size with the correct background color and iamge format.
Have variables for the current drawing location (x & y).
Have variables for the current row and column in your layout.
In a loop, Create your Graphics object.
Use Graphics.DrawImage to add your loaded image to the layout bitmap.
Increment your drawing row and or column as appropriate.
Calculate your new drawing location.
Repeat until done.
One of the options is to use WriteableBitmapEx
Also you can probably find an answer to your question here: How can I merge two images into one?
I'm working on a silverlight project where users get to create their own Collages.
The problem
When loading a bunch of images by using the BitmapImage class, Silverlight hogs up huge unreasonable amounts of RAM. 150 pictures where single ones fill up at most 4,5mb takes up about 1,6GB of RAM--thus ending up throwing memory exceptions.
I'm loading them through streams, since the user selects their own photos.
What I'm looking for
A class, method or some process to eliminate the huge amount of RAM being sucked up. Speed is an issue, so I don't want to be converting between images formats or anything like that. A fast resizing solution might work.
I've tried using a WriteableBitmap to render the images into, but I find this method forces me to reinvent the wheel when it comes to drag/drop and other things I want users to be able to do with the images.
What I would try is to take load each stream and resize it to a thumbnail (say, 640x480) before loading the next one. Then let the user work with the smaller images. Once you're ready to generate the PDF, reload the JPEGs from the original streams one at a time, disposing of each bitmap before loading the next.
I'm guessing you're doing something liek this:
Bitmap bitmap = new Bitmap (filename of jpeg);
and then doing:
OnPaint (...)
{
Graphics g = ....;
g.DrawImage (bitmap, ...);
}
This will be resizing the huge JPEG image to the size shown on screen every time you draw it. I'm guessing your JPEG is about 2500x2000 pixels in size. When you load a JPEG into a Bitmap, the bitmap loading code uncompresses the data and stores it either as RGB data in a format that will be easy to render (i.e. in the same pixel format as the display) or as a thing known as a Device Independant Bitmap (aka DIBitmap). These bitmaps require more RAM to store than a compressed JPEG.
Your current implementation is already doing format conversion and resizing, but doing it in an innefficent way, i.e. resizing a huge image down to screen size every time it's rendered.
Ideally, you want to load the image and scale it down. .Net has a system to do this:
Bitmap bitmap = new Bitmap (filename of JPEG);
Bitmap thumbnail = bitmap.GetThumbnailImage (width, height, ....);
bitmap.Dispose (); // this releases all the unmanged resources and makes the bitmap unusable - you may have been missing this step
bitmap = null; // let the GC know the object is no longer needed
where width and height are the size of the required thumbnail. Now, this might produce images that don't look as good as you might want them to (but it will use any embedded thumbnail data if it's present so it'll be faster), in which case, do a bitmap->bitmap resize.
When you create the PDF file, you'll need to reload the JPEG data, but from a user's point of view, that's OK. I'm sure the user won't mind waiting a short while to export the data to a PDF so long as you have some feedback to let the user know it's being worked on. You can also do this in a background thread and let the user work on another collage.
What might be happening to you is a little known fact about the garbage collection that got me as well. If an object is big enough ( I don't remember where the line is exactly ) Garbage Collection will decide that even though nothing currently in scope is linked to the object (in both yours and mine the objects are the images) it keeps the image in memory because it has decided that in case you ever want that image again it is cheaper to keep it around rather than delete it and reload it later.
This isn't a complete solution, but if you're going to be converting between bitmaps and JPEG's (and vice versa), you'll need to look into the FJCore image library. It's reasonably simple to use, and allows you to do things like resize JPEG images or move them to a different quality. If you're using Silverlight for client-side image processing, this library probably won't be sufficient, but it's certainly necessary.
You should also look into how you're presenting the images to the user. If you're doing collages with Silverlight, presumably you won't be able to use virtualizing controls, since the users will be manipulating all 150 images at once. But as other folks have said, you should also make sure you're not presenting bitmaps based on full-sized JPEG files either. A 1MB compressed JPEG is probably going to expand to a 10MB Bitmap, which is likely where a lot of your trouble is coming from. Make sure that you're basing the images you present to the user on much smaller (lower quality and resized) JPEG files.
The solution that finally worked for me was using WriteableBitmapEX to do the following:
Of course I only use thumbnails if the image isn't already small enough to store in memory.
The gotch'a I had was the fact that WriteableBitmap doesn't have a parameterless constructor, but initializing it with 0,0 as size and then loading the source sets these automatically. That didn't come naturally to me.
Thanks for the help everybody!
private WriteableBitmap getThumbnailFromBitmapStream(Stream bitmapStream, PhotoFrame photoFrame)
{
WriteableBitmap inputBitmap = new WriteableBitmap(0,0);
inputBitmap.SetSource(bitmapStream);
Size thumbnailSize = getThumbnailSizeFromWriteableBitmap(inputBitmap, photoFrame.size);
WriteableBitmap thumbnail = new WriteableBitmap(0,0);
thumbnail = inputBitmap.Resize((int)thumbnailSize.Width, (int)thumbnailSize.Height, WriteableBitmapExtensions.Interpolation.NearestNeighbor);
return thumbnail;
}
One additional variant to reduce ram using:
Dont load images, which ar invisible at this moment, and load them while user scrolling the page. This method uses by web developers to improve page load speed. For you its the way not to store hole amount of images in ram.
And I think the better way not to make thumbnails on run, but store them near the fullsize pictures and get only links for them. When it needed, you alway can get the link to fullsize picture and load it.