【问题标题】:asp.net version of timthumb php classtimthumb php类的asp.net版本
【发布时间】:2011-05-25 02:04:34
【问题描述】:

有人知道著名的 PHP 类“timthumb”的 ASP.Net 版本吗?只需要一个脚本,它可以在“timthumb”的同一行中工作,并为任何尺寸的图像生成高质量的正方形或基于比例的缩略图。

这里是php类的链接:http://www.darrenhoyt.com/2008/04/02/timthumb-php-script-released/

【问题讨论】:

  • 如果我的赏金获奖答案在某些方面不能满足您的需求,请告诉我,我可能会根据您的需求对其进行调整。
  • imageresizing.net 具有几乎相同的语法:?width=x&height=y&quality=0-100

标签: php asp.net thumbnails


【解决方案1】:

我只是为你写的:) ...我通过尝试http://www.binarymoon.co.uk/demo/timthumb-basic/ 中的所有案例来测试它,并将它与我的代码并排进行视觉比较。据我所知,它基本上是相同的。话虽如此,它不支持'zc'标志。

我将其编写为通用处理程序(ashx 文件),以便它运行得更快。支持图像缓存,但我将其注释掉,因为它使测试修复变得非常困难。随意取消注释以提高长期性能(在将其写入内存流时,在开始时一个块,在接近结束时一个块)。

---代码---

<%@ 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

---测试用例---

<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 />

【讨论】:

  • 非常感谢,获得了赏金,虽然我还没有时间自己测试这段代码。
  • 感谢您的信任和赏金 :)
  • 这段代码中存在一些内存泄漏...查看the image resizing pitfalls 并确保您已经避免了所有这些...
  • @Computer Linguist - 感谢您的链接,那里有很好的信息,我发布的代码当然可以从一些 using 语句中受益。但请记住,内存泄漏与暂时未清理但仍会清理的内存之间存在差异。
  • 正确 - 不幸的是,并非所有 System.Drawing 类都正确实现 IDisposable。留给the GC will crash the server under load
【解决方案2】:

@Peter 感谢您提供上面的代码,它在我的 ashx 文件中完美运行。我是 asp.net c# 开发人员,因此我已将您的 vb 代码转换为 c# 并修复了我遇到的一些问题。

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;
            }
        }
    }
}

【讨论】:

    【解决方案3】:

    看起来你想做这样的事情: http://www.4guysfromrolla.com/articles/012203-1.aspx

    最坏的情况,timthumb 是开源的,因此您可以在 .NET 中创建它并将其开源给全世界! (当然要适当注明出处)

    【讨论】:

      【解决方案4】:

      http://imageresizing.net 库完成了 TimThumb 脚本所做的一切,甚至更多。它非常易于安装,并且得到全面支持。

      TimThumb:image.jpg?w=100&h=100&q=90

      ImageResizing.Net:image.jpg?width=100&height=100&quality=100

      如果您需要模仿 timthumb 的确切语法,请告诉我,我可以为您提供几行代码,使其工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-07
        • 2010-12-29
        • 1970-01-01
        • 2023-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-25
        相关资源
        最近更新 更多