Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

asp.net version of timthumb php class

Anyone know of a ASP.Net version of the famous PHP class "timthumb"? Just need a script which will work in the same line of "timthumb" and produce square or ratio based thumbnails with good quality for any sized images.

Here is the link to the php class: http://www.darrenhoyt.com/2008/04/02/timthumb-php-script-released/

like image 768
Kunal Avatar asked Dec 21 '22 20:12

Kunal


2 Answers

@Peter thank you for your code above, it works perfectly in my ashx file. I'm a asp.net c# developer so I have converted your vb code to c# and have fixed up some issues that I encountered.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace myProject.Handlers
{
    public class Thumb : IHttpHandler
    {
        private static int _DefaultWidth = 100;
        private static int _DefaultHeight = 100;
        private static int _DefaultQuality = 90;

        public void ProcessRequest(HttpContext context)
        {
            string imgPath = context.Request.QueryString["src"];

            if (string.IsNullOrEmpty(imgPath))
            {
                context.Response.End();
            }

            string serverPath = context.Server.MapPath(imgPath);
            if (!File.Exists(serverPath))
            {
                context.Response.End();
            }

            Image img = Bitmap.FromFile(serverPath);
            double origRatio = (Math.Min(img.Width, img.Height) / Math.Max(img.Width, img.Height));

            int destWidth = 0;
            int destHeight = 0;
            double destRatio = 0;
            double dHeight = 0;
            double dWidth = 0;

            string qW = context.Request.QueryString["w"];
            string qH = context.Request.QueryString["h"];

            if (!string.IsNullOrEmpty(qW))
            {
                Int32.TryParse(qW, out destWidth);
                if (destWidth < 0)
                {
                    destWidth = 0;
                }
            }

            if (!string.IsNullOrEmpty(qH))
            {
                Int32.TryParse(qH, out destHeight);
                if (destHeight < 0)
                {
                    destHeight = 0;
                }
            }

            if (destWidth == 0 & destHeight == 0)
            {
                destWidth = _DefaultWidth;
                destHeight = _DefaultHeight;
            }
            else if (destWidth > 0 & destHeight > 0)
            {
                //do nothing, we have both sizes already
            }
            else if (destWidth > 0)
            {
                dHeight = double.Parse(destWidth.ToString()) / double.Parse(img.Width.ToString());
                destHeight = int.Parse(Math.Floor(img.Height * dHeight).ToString());
            }
            else if (destHeight > 0)
            {
                dWidth = double.Parse(destHeight.ToString()) / double.Parse(img.Height.ToString());
                destWidth = int.Parse(Math.Floor(img.Width * dWidth).ToString());
            }

            destRatio = (Math.Min(destWidth, destHeight) / Math.Max(destWidth, destHeight));

            int sourceWidth = img.Width;
            int sourceHeight = img.Height;

            int sourceX = 0;
            int sourceY = 0;

            int cmpx = img.Width / destWidth;
            int cmpy = img.Height / destHeight;

            if (cmpx > cmpy)
            {
                sourceWidth = img.Width / cmpx * cmpy;
                sourceX = ((img.Width - (img.Width / cmpx * cmpy)) / 2);
            }
            else if (cmpy > cmpx)
            {
                sourceHeight = img.Height / cmpy * cmpx;
                sourceY = ((img.Height - (img.Height / cmpy * cmpx)) / 2);
            }

            Bitmap bmpThumb = new Bitmap(destWidth, destHeight);
            Graphics g = Graphics.FromImage(bmpThumb);
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.SmoothingMode = SmoothingMode.AntiAlias;

            g.DrawImage(img, new Rectangle(0, 0, destWidth, destHeight), new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), GraphicsUnit.Pixel);

            ImageCodecInfo ici = ImageCodecInfo.GetImageEncoders().Where(c => c.MimeType == "image/jpeg").First();

            MemoryStream ms = new MemoryStream();
            bmpThumb.Save(ms, ici, BuildQualityParams(context));

            WriteImage(ms, context);
        }

        private void WriteImage(MemoryStream ms, HttpContext context)
        {
            context.Response.Clear();

            context.Response.ContentType = "image/jpeg";

            ms.WriteTo(context.Response.OutputStream);

            context.Response.Flush();
            context.Response.End();
        }

        private EncoderParameters BuildQualityParams(HttpContext context)
        {
            EncoderParameters epParams = new EncoderParameters(1);

            int q = _DefaultQuality;

            string strQ = context.Request.QueryString["q"];
            if (!string.IsNullOrEmpty(strQ))
            {
                Int32.TryParse(strQ, out q);
            }

            epParams.Param[0] = new EncoderParameter(Encoder.Quality, q);

            return epParams;
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}
like image 38
Jonty Avatar answered Jan 01 '23 14:01

Jonty


I wrote this up just for you :) ... I tested it by trying all of the cases in http://www.binarymoon.co.uk/demo/timthumb-basic/ and comparing it visually side by side with my code. As far as I can tell it's basically identical. With that said it does not support the 'zc' flag.

I wrote it as a generic handler (ashx file) so that it should run faster. Imaging caching is supported but I commented it out since it makes testing fixes very tough. Feel free to uncomment it for improved performance over the long run (one block right at the beginning and one near the end when it writes it to the memory stream).

---Code---

<%@ WebHandler Language="VB" Class="Thumb" %>

    Imports System
    Imports System.Web
    Imports System.Drawing
    Imports System.IO

    Public Class Thumb : Implements IHttpHandler
        Private Shared _DefaultWidth As Integer = 100
        Private Shared _DefaultHeight As Integer = 100
        Private Shared _DefaultQuality As Integer = 90

        Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
            ''check the cache for the image first
            'Dim cacheObj As Object = context.Cache("Thumb-" + context.Request.Url.ToString().ToLower())
            'If cacheObj IsNot Nothing Then
            '    Dim msCache As MemoryStream = DirectCast(cacheObj, MemoryStream)

            '    WriteImage(msCache, context)

            '    Exit Sub
            'End If

            'process request (since it wasn't in the cache)
            Dim imgPath As String = context.Request.QueryString("src")

            If String.IsNullOrEmpty(imgPath) Then
                context.Response.End()
            End If

            'get image path on server
            Dim serverPath As String = context.Server.MapPath(imgPath)
            If Not File.Exists(serverPath) Then
                context.Response.End()
            End If

            'load image from file path
            Dim img As Image = Bitmap.FromFile(serverPath)
            Dim origRatio As Double = (Math.Min(img.Width, img.Height) / Math.Max(img.Width, img.Height))

            '---Calculate thumbnail sizes---
            Dim destWidth As Integer = 0
            Dim destHeight As Integer = 0
            Dim destRatio As Double = 0

            Dim qW As String = context.Request.QueryString("w")
            Dim qH As String = context.Request.QueryString("h")

            If Not String.IsNullOrEmpty(qW) Then
                Int32.TryParse(qW, destWidth)
                If destWidth < 0 Then
                    destWidth = 0
                End If
            End If

            If Not String.IsNullOrEmpty(qH) Then
                Int32.TryParse(qH, destHeight)
                If destHeight < 0 Then
                    destHeight = 0
                End If
            End If

            'if both width and height are 0 then use defaults (100x100)
            If destWidth = 0 And destHeight = 0 Then
                destWidth = _DefaultWidth
                destHeight = _DefaultHeight

                'else, if the width is specified, calculate an appropriate height
            ElseIf destWidth > 0 And destHeight > 0 Then
                'do nothing, we have both sizes already
            ElseIf destWidth > 0 Then
                destHeight = Math.Floor(img.Height * (destWidth / img.Width))
            ElseIf destHeight > 0 Then
                destWidth = Math.Floor(img.Width * (destHeight / img.Height))
            End If

            destRatio = (Math.Min(destWidth, destHeight) / Math.Max(destWidth, destHeight))

            'calculate source image sizes (rectangle) to get pixel data from        
            Dim sourceWidth As Integer = img.Width
            Dim sourceHeight As Integer = img.Height

            Dim sourceX As Integer = 0
            Dim sourceY As Integer = 0

            Dim cmpx As Integer = img.Width / destWidth
            Dim cmpy As Integer = img.Height / destHeight

            'selection is based on the smallest dimension
            If cmpx > cmpy Then
                sourceWidth = img.Width / cmpx * cmpy
                sourceX = ((img.Width - (img.Width / cmpx * cmpy)) / 2)
            ElseIf cmpy > cmpx Then
                sourceHeight = img.Height / cmpy * cmpx
                sourceY = ((img.Height - (img.Height / cmpy * cmpx)) / 2)
            End If

            '---create the new thumbnail image---
            Dim bmpThumb As New Bitmap(destWidth, destHeight)
            Dim g = Graphics.FromImage(bmpThumb)
            g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
            g.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
            g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

            g.DrawImage(img, _
                        New Rectangle(0, 0, destWidth, destHeight), _
                        New Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), GraphicsUnit.Pixel)

            '-----write out Thumbnail to the output stream------        
            'get jpeg image coded info so we can use it when saving
            Dim ici As Imaging.ImageCodecInfo = Imaging.ImageCodecInfo.GetImageEncoders().Where(Function(c) c.MimeType = "image/jpeg").First()

            'save image to memory stream
            Dim ms As New MemoryStream()
            bmpThumb.Save(ms, ici, BuildQualityParams(context))

            ''save image to cache for future use
            'context.Cache("Thumb-" + context.Request.Url.ToString().ToLower()) = ms

            'write the image out
            WriteImage(ms, context)
        End Sub

        Private Sub WriteImage(ByVal ms As MemoryStream, ByVal context As HttpContext)
            'clear the response stream
            context.Response.Clear()

            'set output content type to jpeg
            context.Response.ContentType = "image/jpeg"

            'write memory stream out
            ms.WriteTo(context.Response.OutputStream)

            'flush the stream and end the response
            context.Response.Flush()
            context.Response.End()
        End Sub

        'for adjusting quality setting if needed, otherwise 90 will be used
        Private Function BuildQualityParams(ByVal context As HttpContext) As Imaging.EncoderParameters
            Dim epParams As New Imaging.EncoderParameters(1)

            Dim q As Integer = _DefaultQuality

            Dim strQ As String = context.Request.QueryString("q")
            If Not String.IsNullOrEmpty(strQ) Then
                Int32.TryParse(strQ, q)
            End If

            epParams.Param(0) = New Imaging.EncoderParameter(Imaging.Encoder.Quality, q)

            Return epParams
        End Function

        Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
            Get
                Return False
            End Get
        End Property
    End Class

---Test Cases---

<img alt="" src="Thumb.ashx?src=~/images/castle1.jpg" /> 
<br />
<img alt="" src="Thumb.ashx?src=~/images/castle1.jpg&q=100" /> 
<br />
<img alt="" src="Thumb.ashx?src=~/images/castle1.jpg&q=10" /> 
<br />
<img alt="" src="Thumb.ashx?src=~/images/castle1.jpg&w=200" /> 
<br />
<img alt="" src="Thumb.ashx?src=~/images/castle1.jpg&h=150" /> 
<br />
<img alt="" src="Thumb.ashx?src=~/images/castle1.jpg&h=180&w=120" /> 
<br />
<img alt="" src="Thumb.ashx?src=~/images/castle1.jpg&h=80&w=210" /> 
<br />
like image 92
Peter Avatar answered Jan 01 '23 13:01

Peter