I am creating MVC4 web site and want to display every allowed picture from database. The problem is that pictures have different size, some of them have portrait orientation and the others have landscape. First of all, all images need to keep aspect ratio. Every image is displayed in div named card and it should have standard size (size I set in <img>
control). So I need to resize image on that way that neither height nor width must exceed dimension height and width of <img>
control. For example, if some image has portrait orientation height mustn't exceed height of <img>
control, so if image has landscape orientation it should be resized on that way thad width mustn't exceed width of <img>
control. I displayed pictures on this way:
Controller
[ChildActionOnly]
public ActionResult _PhotoGallery(int number)
{
List<Photo> photos;
if (number == 0)
{
photos = context.FindAllUnVisiblePhotos(true).OrderByDescending(x => x.CreatedDate).ToList();
}
else
{
photos = context.FindAllUnVisiblePhotos(true).OrderByDescending(x => x.CreatedDate).Take(number).ToList();
}
return PartialView("_PhotoGallery", photos);
}
View
@foreach (var item in Model)
{
<div class="photo-index-card">
<div style="float:left; padding: 2px 2px 2px 2px; margin: 0px 0px 10px 0px; height: 20px;">
<div>@item.Title</div>
</div>
<div style="float:left;">
@if (item.PhotoFile != null)
{
<a href="@Url.Action("Display", "Photo", new { id = item.PhotoID })">
<img class="photo-index-card-img" src="@Url.Action("GetImage", "Photo", new { id = item.PhotoID })" />
</a>
}
</div>
</div>
}
GetImage
public FileContentResult GetImage(int id)
{
Photo photo = context.FindPhotoById(id);
if (photo.PhotoFile != null)
{
return File(photo.PhotoFile, photo.ImageMimeType);
}
else
{
return null;
}
}
How could I resize images to fit requrements?
The only way it's to crop the portrait photos to fit in the image. I have this VB function that do exactly as you say, cropping 25% of the extra height pixel from the top, and the rest from the botton. The majority of the photos looks ok this way. I'm using this in a tourism website.
Public Shared Function SaveAsThumbnailCropped(ByVal path As String, ByVal archivo As String, ByVal NewWidth As Integer, ByVal NewHeight As Integer) As String
' Declare two variables of type Integer named
' adjustedImageWidth and adjustedImageHeight.
Dim adjustedImageWidth, adjustedImageHeight As Integer
' Declare a variable named theImage of type Image.
Dim theImage As Image
Dim ThumbFileName, extension As String, convertToGIF As Boolean = False
If InStrRev(archivo, ".") > 0 Then
extension = Mid(archivo, InStrRev(archivo, ".")).ToString.ToLower
ThumbFileName = Mid(archivo, 1, InStrRev(archivo, ".") - 1) + "_tb" + Trim(NewWidth) + "x" + Trim(NewHeight) + extension
Else
extension = "" 'desconocida
ThumbFileName = archivo + "_tb" + Trim(NewWidth) + "x" + Trim(NewHeight)
End If
If Not My.Computer.FileSystem.FileExists(path + "\" + ThumbFileName) And My.Computer.FileSystem.FileExists(path + "\" + archivo) Then
' Get an image object from the image file;
' assign the image object to the theImage variable.
theImage = System.Drawing.Image.FromFile(path + "\" + archivo)
If theImage.Height > NewHeight Or theImage.Width > NewWidth Then
If theImage.Height * NewWidth / theImage.Width > NewHeight Then
' tengo que reducir el alto
adjustedImageHeight = NewHeight
'keep ratio
adjustedImageWidth = theImage.Width * (adjustedImageHeight / theImage.Height)
Else
adjustedImageWidth = NewWidth
'keep ratio
adjustedImageHeight = theImage.Height * (adjustedImageWidth / theImage.Width)
End If
Else
'no hago nada porque la imagen es muy chica
Return archivo
End If
Dim cropRect As Rectangle
If adjustedImageHeight < NewHeight Or adjustedImageWidth > NewWidth Then
'era muy apaisada tengo que croppear el centro
adjustedImageHeight = NewHeight
adjustedImageWidth = theImage.Width * (adjustedImageHeight / theImage.Height)
Dim WidthSobrante = adjustedImageWidth - NewWidth
cropRect = New Rectangle(WidthSobrante / 2, 0, NewWidth, NewHeight)
ElseIf adjustedImageHeight > NewHeight Or adjustedImageWidth < NewWidth Then
adjustedImageWidth = NewWidth
adjustedImageHeight = theImage.Height * (adjustedImageWidth / theImage.Width)
'quedo muy larga. Le cropeo el 25% de arriba del sobrante
Dim HeightSobrante = adjustedImageHeight - NewHeight
cropRect = New Rectangle(0, HeightSobrante / 4, NewWidth, NewHeight)
Else
cropRect = New Rectangle(0, 0, Math.Min(NewWidth, theImage.Width), Math.Min(NewHeight, theImage.Height))
End If
Dim Image As System.Drawing.Image = theImage
Dim thumbnail As System.Drawing.Image = New Bitmap(adjustedImageWidth, adjustedImageHeight)
Dim graphic As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(thumbnail)
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic
graphic.SmoothingMode = SmoothingMode.HighQuality
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality
graphic.CompositingQuality = CompositingQuality.HighQuality
graphic.DrawImage(Image, 0, 0, adjustedImageWidth, adjustedImageHeight)
Dim croppedThumbnail = cropImage(thumbnail, cropRect)
If extension.Equals(".gif") Then
Dim quantizer As ImageQuantization.OctreeQuantizer = New ImageQuantization.OctreeQuantizer(255, 8)
Dim quantized As Bitmap = quantizer.Quantize(croppedThumbnail)
quantized.Save(path + "\" + ThumbFileName, System.Drawing.Imaging.ImageFormat.Gif)
ElseIf extension.Equals(".jpg") Or extension.Equals(".jpeg") Then
'Create quality parameter
Dim encoderParams As New EncoderParameters(1)
Dim jpgCodec As ImageCodecInfo
jpgCodec = GetImageCodec("image/jpeg")
If Not jpgCodec Is Nothing Then
'Create quality parameter
Dim qParam As New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L)
encoderParams.Param(0) = qParam
croppedThumbnail.Save(path + "\" + ThumbFileName, jpgCodec, encoderParams)
End If
Else
croppedThumbnail.Save(path + "\" + ThumbFileName)
End If
croppedThumbnail.Dispose()
thumbnail.Dispose()
Image.Dispose()
graphic.Dispose()
End If
Return ThumbFileName
End Function
Private Shared Function cropImage(img As Image, cropArea As Rectangle) As Image
Dim bmpImage = New Bitmap(img)
Dim bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat)
Return CType(bmpCrop, Image)
End Function
Private Shared Function GetImageCodec(ByVal mimeType As String) As ImageCodecInfo
Dim codecs() As ImageCodecInfo = ImageCodecInfo.GetImageEncoders()
For Each codec As ImageCodecInfo In codecs
If codec.MimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase) Then
Return codec
End If
Next
Return Nothing
End Function
Thanks Eduardo, you helped me to find solution. I modified GetImage method so it secure that every dimension of image is less than wanted one. Code will explain more than words:
public FileContentResult GetImage(int id, int w, int h)
{
Photo photo = context.FindPhotoById(id);
MemoryStream ms;
if (photo.PhotoFile != null)
{
if (w != 0 && h != 0)
{
ms = new MemoryStream(photo.PhotoFile);
Image img = Image.FromStream(ms);
var ratio = (double)img.Width / (double)img.Height;
var ratioImg = (double)w / (double)h;
var newHeight = 0;
var newWidth = 0;
if (img.Height > img.Width)
{
newHeight = h;
newWidth = (int)(ratio * newHeight);
}
else
{
newWidth = w;
newHeight = (int)(newWidth / ratio);
}
var newImage = new Bitmap(newWidth, newHeight);
var destRect = new Rectangle(0, 0, newWidth, newHeight);
using (var graphics = Graphics.FromImage(newImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(img, destRect, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, wrapMode);
}
}
Bitmap bmp = new Bitmap(newImage);
ImageConverter icnv = new ImageConverter();
var imgByte = (byte[])icnv.ConvertTo(bmp, typeof(byte[]));
return File(imgByte, photo.ImageMimeType);
}
else
{
return File(photo.PhotoFile, photo.ImageMimeType);
}
}
else
{
return null;
}
}
So, if the image has portrait orientation, method sets its height to wanted height and sets width maintaining the aspect ratio so that height cannot exceed max height. If the image has landscape orientation method sets width to wanted and sets height keeping aspect ratio.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.