I am using the following code in my website, for thumbnail creation:
string furl = "~/images/thumbs/" + matchString;
lBlogThumb.ImageUrl = GetThumbnailView(furl, 200, 200);
private string GetThumbnailView(string originalImagePath, int height, int width)
{
//Consider Image is stored at path like "ProductImage\\Product1.jpg"
//Now we have created one another folder ProductThumbnail to store thumbnail image of product.
//So let name of image be same, just change the FolderName while storing image.
string thumbnailImagePath = originalImagePath.Replace("thumbs", "thumbs2");
//If thumbnail Image is not available, generate it.
if (!System.IO.File.Exists(Server.MapPath(thumbnailImagePath)))
{
System.Drawing.Image imThumbnailImage;
System.Drawing.Image OriginalImage = System.Drawing.Image.FromFile(Server.MapPath(originalImagePath));
imThumbnailImage = OriginalImage.GetThumbnailImage(width, height,
new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
imThumbnailImage.Save(Server.MapPath(thumbnailImagePath), System.Drawing.Imaging.ImageFormat.Jpeg);
imThumbnailImage.Dispose();
OriginalImage.Dispose();
}
return thumbnailImagePath;
}
public bool ThumbnailCallback() { return false; }
I would like to change this code, and be able to create a thumbnail defining width ONLY. What I have in mind is actually something like cropping/resizing image, using a static width, maintaining it's ratio. Is that possible;
You mention resizing and cropping. If you want the thumbnail heights to vary with a fixed width, the answers provided already will work for you.
The mention of cropping makes me think that you may want a fixed thumbnail size, with the width filled and any overflowing vertical portion cropped off. If that is the case, you'll need to do a bit more work. I needed something similar recently, and this is what I came up with.
This will create a thumbnail of the original that is sized and cropped in such a way that the source image completely fills the target thumbnail, cropping any overflow. There will be no borders within the thumbnail, even if the original and thumbnail aspect ratios are different.
public System.Drawing.Image CreateThumbnail(System.Drawing.Image image, Size thumbnailSize)
{
float scalingRatio = CalculateScalingRatio(image.Size, thumbnailSize);
int scaledWidth = (int)Math.Round((float)image.Size.Width * scalingRatio);
int scaledHeight = (int)Math.Round((float)image.Size.Height * scalingRatio);
int scaledLeft = (thumbnailSize.Width - scaledWidth) / 2;
int scaledTop = (thumbnailSize.Height - scaledHeight) / 2;
// For portrait mode, adjust the vertical top of the crop area so that we get more of the top area
if (scaledWidth < scaledHeight && scaledHeight > thumbnailSize.Height)
{
scaledTop = (thumbnailSize.Height - scaledHeight) / 4;
}
Rectangle cropArea = new Rectangle(scaledLeft, scaledTop, scaledWidth, scaledHeight);
System.Drawing.Image thumbnail = new Bitmap(thumbnailSize.Width, thumbnailSize.Height);
using (Graphics thumbnailGraphics = Graphics.FromImage(thumbnail))
{
thumbnailGraphics.CompositingQuality = CompositingQuality.HighQuality;
thumbnailGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
thumbnailGraphics.SmoothingMode = SmoothingMode.HighQuality;
thumbnailGraphics.DrawImage(image, cropArea);
}
return thumbnail;
}
private float CalculateScalingRatio(Size originalSize, Size targetSize)
{
float originalAspectRatio = (float)originalSize.Width / (float)originalSize.Height;
float targetAspectRatio = (float)targetSize.Width / (float)targetSize.Height;
float scalingRatio = 0;
if (targetAspectRatio >= originalAspectRatio)
{
scalingRatio = (float)targetSize.Width / (float)originalSize.Width;
}
else
{
scalingRatio = (float)targetSize.Height / (float)originalSize.Height;
}
return scalingRatio;
}
To use with your code, you could replace your call to OriginalImage.GetThumbnailImage with this:
imThumbnailImage = CreateThumbnail(OriginalImage, new Size(width, height));
Note that for portrait images, this code will actually shift the thumbnail's viewport slightly higher on the original image. This was done so that portrait shots of people wouldn't result in headless torsos when the thumbnails were created. If you don't want that logic, simply remove the if block following the "portrait mode" comment.
let's have originalWidth=the original image width and thumbWidth. You can simply choose the thumbWidth to your desired value, and calculate the thumbHeigth=originalHeigth*thumbWidth/originalWidth
I got sick of needed to do this and created a lib that does this easily: Link To Documentation & Download
A basic example without rounding with a thumbnail width of 140, below the 'file' is a HttpPostedFile uploaded from an ASP.Net FileUpload control, the HttpPostedFile exposes a stream.
// Save images to disk.
using (System.Drawing.Image image = System.Drawing.Image.FromStream(file.InputStream))
using (System.Drawing.Image thumbnailImage = image.GetThumbnailImage(140, Convert.ToInt32((image.Height / (image.Width / 140))), null, IntPtr.Zero))
{
if (image != null)
{
image.Save(imageFilePath);
thumbnailImage.Save(thumbnailImagePath);
}
else
throw new ArgumentNullException("Image stream is null");
}
Related
I'm making an app that can save to PDF image of my controls (datagrids etc).
The controls are big - width and height, with scrolls.
And my app can paginate view of this controls for saving to PDF or can save without paginating.
If i add my control to Fixed Page, it works fine, the quality is superior, but it takes a long time to save such file and it "eats" lot of space. But if i firstly make a bitmap image of this control, then save it to PDF, the quality is getting poor for some page sizes, though it makes PDF file much more lightweight.
The process goes that way:
Paginating (or not - depends on settings) with visualbrush - > Make a bitmap (bmp) -> Save to PDF.
If my page size is about A4, A3 or A2 - the quality is OK. But if i set bigger size - A1 or A0, the quality is getting so poor, that text can't be read.
If i make some other way: Paginating (or not - depends on settings) with visualbrush - > Save to PDF - without part of making bitmap image of my control, everything is good, A1 and A0 ...and even bigger page sizes looks good, but PDF file becomes much more bigger and it takes more time to save.
Is this because of some bitmap features for big sizes or something goes wrong? I mean, why the quality for A4, A3 and A2 sizes is OK, and for bigger sizes is poor?
I've also tried to change dpi or render sizes and some other attributes, but i couldn't get some good result.
Here is my code for making image of control:
private Image GetPageImage(FrameworkElement element, Size pageSize, double dpiX = 0, double dpiY = 0)
{
//Get current dpi
if (dpiX == 0 || dpiY == 0) { dpiX = PrintProperties.GetDpi()[0];dpiY = PrintProperties.GetDpi()[1]; }
//Check element measure
if (!element.IsMeasureValid)
{
Size size = new Size(element.Width, element.Height);
element.Measure(size);
element.Arrange(new Rect(size));
}
element.ApplyTemplate();
element.UpdateLayout();
Image pageImage = new Image();
double renderHeight = element.Height;
double renderWidth = element.Width;
if (element.DesiredSize.Width > (pageSize.Width-2*_margin) || element.DesiredSize.Height> (pageSize.Height-2*_margin))
{
if(element.Height>element.Width)
{
renderHeight = pageSize.Height - _margin * 2;
renderWidth = element.Width*(renderHeight / element.Height);
}
else
{
renderWidth = pageSize.Width - _margin * 2;
renderHeight = element.Height * (renderWidth / element.Width);
}
}
element.RenderSize = new Size(renderWidth, renderHeight);
var rect = new Rect(element.RenderSize);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
dc.DrawRectangle(new VisualBrush(element), null, rect);
}
var bitmap = new RenderTargetBitmap((int)element.Width, (int)element.Height, dpiX, dpiY, PixelFormats.Default);
bitmap.Render(visual);
pageImage.Source = bitmap;
return pageImage;
}
In my project, I want to generate thumbnail from images that uploaded by user and show it in a gallery ( showing in a div box with size : 180 x 250). Below is code that i'm using to do it.
Size thumbnailSize = GetThumbnailSize(img);
System.Drawing.Image thumbnail = img.GetThumbnailImage(thumbnailSize.Width, thumbnailSize.Height, null, IntPtr.Zero);
.....
private Size GetThumbnailSize(System.Drawing.Image original)
{
const int maxPixels = 300;
int originalWidth = original.Width;
int originalHeight = original.Height;
double factor;
if (originalWidth > originalHeight)
{
factor = (double)maxPixels / originalWidth;
}
else
{
factor = (double)maxPixels / originalHeight;
}
return new Size((int)(originalWidth * factor), (int)(originalHeight * factor));
}
My problem is, the generated thumbnail is only suitable for image that large size, when user upload image that are smaller(eg:30 x 30), the thumbnail that generated will be zoom in and not clear shown like below. So what to do in order to generate thumbnail that are in ratio and can show properly in my gallery div box no matter the image is large or small?
I would recommend to check if the Image is smaller then the size you want to have. If it is not treat it like you allready do. If it is smaller copy the image data into the center of a blank image that has the size you want to have and display this as thumbnail.
I have used the code from http://www.codeproject.com/Tips/552141/Csharp-Image-resize-convert-and-save to resize images programmatically. However, that project uses the System.Drawing libraries, which are not available to Windows 10 applications.
I have tried using the BitmapImage class from Windows.UI.Xaml.Media.Imaging instead, but it does not seem to offer the functionality that was found in System.Drawing..
Has anyone had any luck being able to resize (scale down) images in Windows 10? My application will be processing images from multiple sources, in different formats/sizes, and I am trying to resize the actual images to save space, rather than just letting the application size it to fit the Image in which it is being displayed.
EDIT
I have modified the code from the above mentioned link, and have a hack which works for my specific need. Here it is:
public static BitmapImage ResizedImage(BitmapImage sourceImage, int maxWidth, int maxHeight)
{
var origHeight = sourceImage.PixelHeight;
var origWidth = sourceImage.PixelWidth;
var ratioX = maxWidth/(float) origWidth;
var ratioY = maxHeight/(float) origHeight;
var ratio = Math.Min(ratioX, ratioY);
var newHeight = (int) (origHeight * ratio);
var newWidth = (int) (origWidth * ratio);
sourceImage.DecodePixelWidth = newWidth;
sourceImage.DecodePixelHeight = newHeight;
return sourceImage;
}
This way seems to work, but ideally rather than modifying the original BitmapImage, I would like to create a new/copy of it to modify and return instead.
Here is a shot of it in action:
I may want to return a copy of the original BitmapImage rather than modifying the original.
There is no good method to directly copy a BitmapImage, but we can reuse StorageFile for several times.
If you just want to select a picture, show it and in the meanwhile show the re-sized picture of original one, you can pass the StorageFile as parameter like this:
public static async Task<BitmapImage> ResizedImage(StorageFile ImageFile, int maxWidth, int maxHeight)
{
IRandomAccessStream inputstream = await ImageFile.OpenReadAsync();
BitmapImage sourceImage = new BitmapImage();
sourceImage.SetSource(inputstream);
var origHeight = sourceImage.PixelHeight;
var origWidth = sourceImage.PixelWidth;
var ratioX = maxWidth / (float)origWidth;
var ratioY = maxHeight / (float)origHeight;
var ratio = Math.Min(ratioX, ratioY);
var newHeight = (int)(origHeight * ratio);
var newWidth = (int)(origWidth * ratio);
sourceImage.DecodePixelWidth = newWidth;
sourceImage.DecodePixelHeight = newHeight;
return sourceImage;
}
In this scenario you just need to call this task and show the re-sized image like this:
smallImage.Source = await ResizedImage(file, 250, 250);
If you want to keep the BitmapImage parameter due to some reasons (like the sourceImage might be a modified bitmap but not directly loaded from file), and you want to re-size this new picture to another one, you will need to save the re-sized picture as a file at first, then open this file and re-size it again.
I save an image in preview mode. Preview mode contains Picturebox and Label control.
The problem is when I save an image. Likely I recorded my screen.
The export image is different with my expect, it does not keep aspect ratio.
So, all control in panel after save to example.jpg will wrong position.
My code use to ScaleImage:
public static Image ScaleImage(Image image, int maxWidth, int maxHeight)
{
var ratioX = (double) maxWidth/image.Width;
var ratioY = (double) maxHeight/image.Height;
var ratio = Math.Min(ratioX, ratioY);
var newWidth = (int) (image.Width*ratio);
var newHeight = (int) (image.Height*ratio);
var newImage = new Bitmap(newWidth, newHeight);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
My code save image:
Graphics g = Graphics.FromImage(img);
string s = lstImgAdded.Items[k].Text;
Bitmap bm = new Bitmap(#"" + s);
panel2.BackgroundImage = bm;
PointF p1 = StretchImageSize(postPoint, panel2);
g.DrawImage(
DrawText(lstAliasImage[i - valuesFrom], fontType, colorInput,
Color.Transparent),
Point.Round(StretchImageSize(postPoint, panel2))); // Point.Round(StretchImageSize(postPoint, panel2)) ở đây dùng nhìu lần
g.DrawImage(ctrl.Image, Point.Round(StretchImageSize(postPointPicturebox, panel2)).X, Point.Round(StretchImageSize(postPointPicturebox, panel2)).Y,
ctrl.Width, ctrl.Height); // panel2 có phải cái hình nhỏ ko? ko. picturebox moi la nho, panel la background lon
g.Dispose();
string linkLocation = txtAddress.Text;
ScaleImage(img, witdhImg, heightImg)
.Save(linkLocation + "\\" + lstAliasImage[i - valuesFrom] + "." + imgType,
ImageFormat.Jpeg);
And class StretchImage to scale control(Picturebox, Label) with a panel.
Image show before image in a panel is different after save.
In my software, Image shown in the panel. It does not scale like in Preview software:
Applying Aspect Ratio to Windows Forms
Much like we intercepted Windows message in our Windows 7 Style Form, to keep the aspect ratio of a Windows Form we are going to intercept the resizing Windows messages. This is done by overriding WndProc.
Here is a list of the constants that we need for this algorithm:
WM_SIZING = 0x214
WMSZ_LEFT = 1
WMSZ_RIGHT = 2
WMSZ_TOP = 3
WMSZ_BOTTOM = 6
The first one is the way our C# application can tell when the Form
is being resized. The rest of the constants tell us exactly which
side of the Form is being resized. Note that for corners the edges
combine. So for example, the lower left corner would be resizing the
right and bottom parts of the form and thus be 2 + 6 = 8.
The advantage of using WndProc instead of Windows Form events is
that we can prevent the Form from flickering. Resize events in .NET
are called until after the resizing has been applied, so modifying
size in an event produces flickering.
Make sure to download the sample C# application. Notice how no
matter where you resize the Form from, the aspect ratio is
maintained. A quick peek at the source code shows how either the
height or width is adjusted depending on which side of the Form was
being resized. Another cool thing is that the Form can still be
maximized to fill the entire screen without any problems.
try this
public void ResizeImage(string OriginalFile, string NewFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider)
{
System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFile);
// Prevent using images internal thumbnail
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
if (OnlyResizeIfWider)
{
if (FullsizeImage.Width MaxHeight)
{
// Resize with height instead
NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
NewHeight = MaxHeight;
}
System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);
// Clear handle to original file so that we can overwrite it if necessary
FullsizeImage.Dispose();
// Save resized picture
NewImage.Save(NewFile);
}
In my site, users can upload photos. I currently compress and resize the photo to make sure they aren't huge files. But this creates photos that are of varying dimensions... which makes the site a bit "ugly" in my opinion.
I'd like to ensure the thumbnails are square images, but not by using padding. It's ok if there is some loss of the photo in the thumbnail. I'd like to keep the fidelity of the photo high, even if it means some cropping needs to occur.
I wrote some code to do this exact thing. I chose to crop it because resizing without preserving aspect ratio looks pretty horrible. I do a crop then a resize to create a thumnail image:
public Bitmap CreateThumbnail(Bitmap RawImage)
{
int width = RawImage.Width;
int height = RawImage.Height;
Size ThumbnailDimensions = new Size();
ThumbnailDimensions.Width = 100;
ThumbnailDimensions.Height = 100;
Rectangle cropArea = new Rectangle();
if (width > height)
{
cropArea.Width = height;
cropArea.Height = height;
cropArea.X = 0;
cropArea.Y = 0;
}
else if (width < height)
{
cropArea.Width = width;
cropArea.Height = width;
cropArea.X = 0;
cropArea.Y = 0;
}
if(width != height) Bitmap thumbnail = CropImage(RawImage, cropArea);
thumbnail = ResizeImage(thumbnail, ThumbnailDimensions);
return thumbnail;
}
This just crops from the top left corner then resizes it to my thumbnail dimensions.
I would imagine you need to take the shortest dimension (either w or h), and use that as your dimension for creating the cropped image, essentially you can crop and then scale the image. Check out this article as an example for cropping an image. Also check out this Stack Overflow question regarding image quality.
Rather than cropping, I would make the div or whatever you put them in a fixed square size. Scale the image to fit inside that square.
How would you decide to crop it? From the top-left? Bottom-right? Center?
To make a rectangle into a square you need to either pad, resize without preserving aspect ratio or crop (or combinations).
Here's some code for cropping
http://snippets.dzone.com/posts/show/1484
(I work for Atalasoft -- in our DotImage Photo SDK), it's
AtalaImage img = new AtalaImage("filename.jpg");
AtalaImage img2 = new CropCommand( /*point and size of crop */).Apply(img).Image;
img2.Save("filename", new JpegEncoder(quality), null);