I'm writing an application to send some images to a third party, and the images must be 200x200 DPI. The image is a Bitmap and is sized at 500 width and 250 height.
The first time I tested the images with the third party, my resolution was incorrect. I merely used image.SetResolution(200,200) to correctly set it to 200x200. This, however, only changed the resolution tag for the image and did not properly, according to my third party technical contact, adjust the image height and width.
Is there a ratio that I can use so that for each X units I increment the resolution, I merely increment the corresponding height or width Y units? I thought that I could just increment resolution without having to increment height or width.
Thank you,
Aaron.
An image stored digitally has no meaningful concept of DPI. DPI comes into play when reproducing an image on a physical device.
You need to adjust the image size with regard to the DPI of the physical device, and the desired size of the output on that device.
For example, if a printer tells you they need an image at 300dpi to fill a space of 4in x 4in then you would provide them a bitmap with a size of 1200x1200 pixels. This image would end up with a physical size of 4in x 4in on a 300dpi output device. On a 600dpi device the same image would have an output size of 2in x 2in.
When dealing with digital images, you usually refer to PPI, which is pixels per inch. DPI is not directly related to digital image resolution.
So, if you look at a image that is 200px by 200px # 200PPI, you will have an image that is 1 inch by 1 inch.
Related
I'm writing an image viewer application that loads large still images. I must be able to zoom in to 1:1 to measure exact pixel coordinates of features in the image. I'm using the Viewport control posted here that works great for zoom and panning. I can load a 150 MP tiff image with BitmapDecoder and its pixel count is correct 14000 x 10000. However, when I assign this bitmap to the Image.Source property it gets decimated to roughly 15MP:
sourceBitmap.PixelWidth = 14204
sourceBitmap.PixelHeight = 10652
After assigning this bitmap to image1.Source we get
image1.Source.Width = 4545.27...
image1.Source.Height = 3408.64...
I'm aware of the unitless context of WPF graphics, and can work back the scale factors to read original coordinates, but there is a risk of rounding errors, and I'm working on a scaled copy that degrades the original image resolution.
According to the Microsoft documentation, a WPF bitmap can be up to 64GB in size, but the Image control seems not to be designed to work with bitmaps larger than 15MP. Setting Stretch to "None" makes things worst. It trims the image to the top left 4545 x 3408 pixels of the source and it displays it very small, almost as a thumbnail instead of 1:1.
Is there any way around this limitation?
In contrast to a BitmapSource's PixelWidth and PixelHeight, the Widthand Height values depend on its DPI (dots per inch), which is a TIFF or EXIF tag in the image file.
The values are identical when the resolution is 96 DPI, otherwise calculated as
Width = PixelWidth * 96 / DpiX
Height = PixelHeight * 96 / DpiY
Apparently, your images are tagged with 300 DPI.
This does in no way affect the pixel count, but just determines the native, unstretched size of the bitmap when it is shown in an Image element or ImageBrush.
Instead of using Width and Height, just keep using PixelWidth and PixelHeight:
var bitmap = (BitmapSource)image1.Source;
var width = bitmap.PixelWidth;
var height = bitmap.PixelHeight;
Quick question:
I have this 1000 x 1000 bitmap image:
and I use this routine to load it:
private BitmapSource initialBitmap = new BitmapImage(new Uri("C:\\Users\\...\\Desktop\\Original.bmp"));
Why after I load it, and right after I step over the above line, I see it as 800 x 800?
P.S I want it to be 1000 x 1000 and without using any Resize functions. It was working and suddenly it is 800*800 !
The values returned by BitmapSource.Width and BitmapSource.Height are not in pixels, but rather WPF's device-independent units, which are always 96 dpi. E.g.:
Gets the width of the bitmap in device-independent units (1/96th inch per unit).
If you want to know the actual pixel width and height, you need to use the PixelWidth and PixelHeight properties.
Your question isn't very specific, but if what you are actually concerned about is having the bitmap display at the same size in which it was authored, then the easiest solution is to make sure you author it at 96 dpi. Whatever program you're using to author the bitmap likely has a place where you can set the bitmap resolution. Typically this can be set with or without changing the pixel dimensions of the image (i.e. scaling the image larger or smaller); you want to do it without scaling the image, so that the pixel dimensions remain the same but the dpi changes to match what WPF is using.
Note that this still won't guarantee the bitmap displays at a specific pixel size. The display resolution can be and often is different from 96 dpi, in which case WPF will scale images to ensure that the physical dimensions of the image (i.e. the dimensions in inches, millimeters, etc.) are correct according to the information in the bitmap. For example, 960 pixels wide at 96 dpi means 10" wide. On a 120 dpi display, this means displaying the bitmap large enough so that its width uses 1200 display pixels.
If you want or need the bitmap to display at exactly the same number of display pixels regardless of the display resolution, then you'll have to set a transform where you display the image to reverse the effect of the scaling that WPF would otherwise do. This requires knowing the display resolution, of course.
Here are some other related Stack Overflow questions which you might find useful:
RenderTargetBitmap renders image of a wrong size
WPF for LCD screen Full HD
Screen Resolution Problem In WPF?
This is by design. Note the MSDN documentation for BitmapSource.Width/Height:
Gets the width of the bitmap in device-independent units (1/96th inch
per unit). (Overrides ImageSource.Width.)
Instead you should use the PixelWidth / PixelHeight property:
Gets the width of the bitmap in pixels.
A rather confusing choice or terms, imo, but there you go..
I am working in a project where each user has a big avatar and a thumbnail of this avatar. The avatar is 150x215 and the thumbnail is 50x50. To generate the thumbnail, the user selects a square area inside the avatar and the system crops and resizes the avatar to generate the thumbnail.
Now I need to have a 70x70 thumbnail. I cannot resize the 50x50 thumbnail because it does not look nice. My idea was to create a tool to find the thumbnail inside the avatar and, using the thumbnail location, generate the new 70x70 image. It was working well until I notice that some thumbnails are not only cropped, they are resized. When the image is resized it loses pixels what makes a pixel-by-pixel comparison impossible (so I can't detect the thumbnail location inside the avatar).
Is there any way to identify where the thumbnail is located(even though it is resized)? I am using EMGU to handle the images.
Thanks for any help
[EDIT1]
Seeing your note, if you had the scaling factors applied to the original avatar, then you could create a temp thumbnail that has the same scaling factor applied, then perform a statistical equivalence check of the thumbnail against the already scaled avatar. What this would look like is finding the "difference image" of the thumbnail against the scaled avatar image for each location the thumbnail can possibly lie within the avatar. for each of these "difference images" add all of the pixel based differences into a combined single numeric difference and store that into a 2D array sized to the dimension of x and y locations the thumbnail can possibly be placed within the scaled avatar image (this will be smaller than the total avatar image size, infact it will be width = avatarWidth - thumbWidth and height = avatarHeight - thumbHeight). After you have calculated all of the single difference instances for this 2D array, simply find the min within the array and that is the top-left pixel location within the scaled avatar to use. You will of course have to take the new scaled size of the 50 x 50 thumb into account when grabbing your 70 x 70 from this calculated top-left point.
You dont (by the way) have to store this 2D array of difference values, You could simply hold a min location that is initialized with the value from the first tested location, and only update if the current location is less than the current min. This would avoid the added storage of the array.
[ORIGINAL]
Once the avatar image has been resized, it has also been interpolated, which for all intensive purposes means that the original pixel information has been mathmatically changed irreversibly.
You may have better luck getting into the original thumbnailing code, and changing the thumbnail code to grab the 70 x 70 px sub-image, then create the 50 x 50 by cropping another 10 px from each side!!! This is assuming you still need both the 50 x50 and the 70 x 70 thumbnails.
When I scan a small picture, the scanner output is a big picture. How can I detect original picture from scanned image?
I think you are confusing physical size with resolution. The photograph you are scanning obviously has a physical size — you can measure this with a ruler. When you scan however, you end up with a picture that has a resolution (pixel size) rather than a physical size and this is controlled by the DPI setting in your scanning software. DPI means dots-per-inch and controls how many dots (pixels) will be created for each inch of your photograph — 300 dpi would result in 300 pixels across for each inch width of your photograph and 300 pixels down for each inch of height. As an example, a photograph 10 inches square would produce a 10 * 300 * 10 * 300 = 9 million pixel (or approximately 9 mega-pixel) image.
Physical size will not actually have much meaning on the computer until you come to print your image again*. Then, you can specify the output DPI — how many pixels make up each inch of your printed document. So if you were to scan at 300 dpi and print at 150 dpi, you would end up with an image that is twice the size of your original (as less pixels are making up each inch so those scanned pixels go twice as far). For example, the 9 million pixels of the above example would be printed 150 for every inch across and down (150² per square inch) thus would produce an image that is 20 inches square.
Physical size and resolution are intertwined, however. The more dpi you scan at, the more information about the original document you preserve which means you can print at much larger sizes without the image appearing pixelated. As an extreme example, if you were to print at 1 dpi, you could make those scanned pixels spread over a huge number of inches but each square inch would be a block of solid colour.
* The web mixes things up in that images are usually handled in pixel form thus their size on screen is dependent upon the user's monitor and page zoom settings.
The ImageList has a method named "Draw":
imageList.Draw(graphics, bounds.X, bounds.Y, bounds.Width, bounds.Height, imgIndex);
I use this method to draw an image on a graphics object of a PrintDocument. When using the original image size (16 x 16 pixels), the image is drawn correct. If however, I change the bounds size, nothing is drawn. Even changing the size to 32 x 32 (double size) has no effect. Nothing is drawn. I need to change the drawn size because of the different dpi ... Where am I gong wrong ?
Edit: The solution seems to be simply to use the g.DrawImage method instead. Why imageList.Draw() doesn't draw is still a mistery to me ...
g.DrawImage(imageList.Images[imgIndex], bounds);
ImageList.Draw() is a bit unusual, it takes advantage of the built-in support that the native image list code inside of Windows has for rendering an image in the list. This is an optimization, it avoids the cost of converting the internal image as stored in the native image list back to a managed Image object.
One side-effect however is that this drawing happens without regard for any of the transforms that were applied to the Graphics object. A 16x16 image in the list is going to be rendered as 16x16 pixels on paper. Which is indeed a bit hard to find back, printers have very high resolution (600 dots per inch is typical), that image turns into a decimal point.
Image lists were really meant to be the source of images for the TreeView and ListView controls, it is not a good general purpose collection object for images. Like a List<Image>. Your workaround is good, the Image property converts the internal bitmap back to a managed Image, Graphics.DrawImage() will then scale it appropriately to get a size on paper that's close to the size on the screen. However with the graininess you get from making an image 6 times larger. Note that you should Dispose() that object.