简体   繁体   中英

MVC4 resize images to max height or max width

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM