Генерация произвольной аватарки под разные форумы
C#,
ASP.NET
На разных форумах и соц сетях требуют аватарки разных размеров, форматов, и прочей фигни. Зачем лезть в редактор, хранить где-то по пять копий одной и той-же картинки, если можно заставить сервак делать это за нас?
Фозьмем например Форум Васи Пупкина. На его форуме можно разместить аватарку размером не выше 80х80. У нас 100х100 к тому-же в png. Первым решением становится юзать скрипт с GET параметрами типа generate_avatar.aspx?width=n&height=y однако форумы на это решение умнее тебя и банят подобные пакости. Но можно обхитрить эту систему простой перезаписью URL в народе называемой «красивыми ссылками».
В красивых ссылках нам поможет URL Rewriter для IIS. Дополнение безплатно и пользуюсь им более полугода. Для других, в том числе и под апач/mod_mono(aspnet)/php, лучше гляньте в документацию. В конечном итоге, нам нужно перезаписать что-то вроде /avatargen/высота-ширина.формат в /avatargen.axd?width=&height&format
Сам генератор делается как HTTP хэндлер (это типа как модуль, только работает немного по другому, об этом пишется в МСДН). Так вот, делаем такой хэндлер:
using System.Linq;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
/// <summary>
/// Класс произвольной генерации автарок
/// </summary>
public class AvatarGen : IHttpHandler {
public AvatarGen() {
}
public bool IsReusable {
get { return true; }
}
public void ProcessRequest(HttpContext context) {
// Где хранится исходное изображение. Лучше всего в хорошем качестве и как минимум 100х100
const string AVSOURCE = "~/av.png";
/*
* Формат строки: /avatargen/<ширина>-<высота>.<формат:png|jpg|gif>
* перенаправится в:
* width=
* height=
* format=
*/
if (
string.IsNullOrEmpty(context.Request.QueryString["width"]) ||
string.IsNullOrEmpty(context.Request.QueryString["height"]) ||
string.IsNullOrEmpty(context.Request.QueryString["format"]))
return;
// отпарсить верные значения
int width = 0, height = 0;
string format = context.Request.QueryString["format"];
if (!int.TryParse(context.Request.QueryString["width"], out width)) return;
if (!int.TryParse(context.Request.QueryString["height"], out height)) return;
if (width <= 0 || height <= 0) return; // что за бред? как можно иметь картинку высотой/шириной в 0 пикселей?
// проверка верных форматов
switch (format) {
case "png":
case "jpg":
case "gif":
break;
default:
return;
}
// загрузить основную картинку
using (MemoryStream msCache = new MemoryStream()) {
using (Image imgOriginal = Image.FromFile(context.Server.MapPath(AVSOURCE))) {
// рисуем новую
using (Image bmpNew = new Bitmap(width, height)) {
Graphics g = Graphics.FromImage(bmpNew);
// высокое качество
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.DrawImage(imgOriginal, new Rectangle(0, 0, width, height));
g.Flush();
// для жипега
EncoderParameter qltyParam = new EncoderParameter(Encoder.Quality, 90L);
EncoderParameters @params = new EncoderParameters(1);
@params.Param[0] = qltyParam;
ImageCodecInfo qltyCodec = ImageCodecInfo.GetImageEncoders().Where(e => e.MimeType.Equals("image/jpeg")).Single();
switch (format) {
case "png":
context.Response.ContentType = "image/png";
bmpNew.Save(msCache, imgOriginal.RawFormat); // если у вас что-то другое кроме ПНГ, лучше изменить
break;
case "jpg":
context.Response.ContentType = "image/jpeg";
bmpNew.Save(msCache, qltyCodec, @params);
break;
case "gif":
context.Response.ContentType = "image/gif";
bmpNew.Save(msCache, ImageFormat.Gif);
break;
default:
return;
}
}
}
context.Response.Clear();
// вывод клиенту
msCache.WriteTo(context.Response.OutputStream);
}
context.Response.End();
}
}
Затем, в web.config прописываем следующее в секции system.webServer/handlers (IIS7 и выше, в шестерке похожее но в system.web/httphandlers):
<add name="Генератор Аватара" verb="GET" path="avatargen.axd" type="AvatarGen" />
И в конце-концов для преобразователя ссылок (system.webServer/rewrite/rules):
<rule name="RewriteUserFriendlyURL2" stopProcessing="true">
<match url="^avatargen/([\d]+)-([\d]+)\.(png|jpg|gif)?$" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="false" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="false" />
</conditions>
<action type="Rewrite" url="avatargen.axd?width={R:1}&height={R:2}&format={R:3}" />
</rule>
И имеем результат:
Пока не нашел ни одного места, где мне сказали, что ссылка левая.