در ادامه مطلب
تغییر اندازه تصاویر #1 ، در این پست میخواهیم نحوه تغییر اندازه تصاویر را در زمان درخواست کاربر بررسی کنیم.
در پست قبلی بررسی کردیم که کاربر میتواند در دوحالت تصاویر دریافتی از کاربران سایت را تغییر اندازه دهد، یکی در زمان ذخیره سازی تصاویر بود و دیگری در زمانی که کاربر درخواست نمایش یک تصویر را دارد.
خوب ابتدا فرض میکنیم برای نمایش تصاویر چند حالت داریم مثلا کوچک، متوسط، بزرگ و حالت واقعی (اندازه اصلی).
البته دقت نمایید که این طبقه بندی فرضی بوده و ممکن است برای پروژههای مختلف این طبقه بندی متفاوت باشد. (در این پست قصد فقط اشنایی با تغییر اندازه تصاویر است و شاید کد به درستی refactor نشده باشد).
برای تغییر اندازه تصاویر در زمان اجرا یکی از روش ها، میتواند استفاده از
Handler باشد. خوب برای ایجاد Handler ابتدا در پروژه وب خود بروی پروژه راست کلیک کرده، و گزینه New Item را برگزینید، و در پنجره ظاهر شده مانند تصویر زیر گزینه Generic Handler را انتخاب نمایید.
پس از ایجاد هندلر، فایل کد آن مانند زیر خواهد بود، ما باید کدهای خود را در متد
ProcessRequestبنویسیم.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace PWS.UI.Handler
{
/// <summary>
/// Summary description for PhotoHandler
/// </summary>
public class PhotoHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
خوب برای نوشتن کد در این مرحله ما باید چند کار انجام دهیم.
1- گرفتن پارامترهای ورودی کاربر جهت تغییر سایز از طریق روشهای انتقال مقادیر بین صفحات (در اینجا استفاده از
Query String ).
2-بازیابی تصویر از دیتابیس یا از دیسک به صورت یک آرایه بایتی.
3- تغییر اندازه تصویر مرحله 2 و ارسال تصویر به خروجی.
using System;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Web;
namespace PWS.UI.Handler
{
/// <summary>
/// Summary description for PhotoHandler
/// </summary>
public class PhotoHandler : IHttpHandler
{
/// <summary>
/// بازیابی تصویر اصلی از بانک اطلاعاتی
/// </summary>
/// <param name="photoId">کد تصویر</param>
/// <returns></returns>
private byte[] GetImageFromDatabase(int photoId)
{
using (var connection = new SqlConnection("ConnectionString"))
{
using (var command = new SqlCommand("Select Photo From tblPhotos Where Id = @PhotoId", connection))
{
command.Parameters.Add(new SqlParameter("@PhotoId", photoId));
connection.Open();
var result = command.ExecuteScalar();
return ((byte[])result);
}
}
}
/// <summary>
/// بازیابی فایل از دیسک
/// </summary>
/// <param name="photoId">با فرض اینکه نام فایل این است</param>
/// <returns></returns>
private byte[] GetImageFromDisk(string photoId /* or somting */)
{
using (var sourceStream = new FileStream("Original File Path + id", FileMode.Open, FileAccess.Read))
{
return StreamToByteArray(sourceStream);
}
}
/// <summary>
/// Streams to byte array.
/// </summary>
/// <param name="inputStream">The input stream.</param>
/// <returns></returns>
/// <exception cref="System.ArgumentException"></exception>
static byte[] StreamToByteArray(Stream inputStream)
{
if (!inputStream.CanRead)
{
throw new ArgumentException();
}
// This is optional
if (inputStream.CanSeek)
{
inputStream.Seek(0, SeekOrigin.Begin);
}
var output = new byte[inputStream.Length];
int bytesRead = inputStream.Read(output, 0, output.Length);
Debug.Assert(bytesRead == output.Length, "Bytes read from stream matches stream length");
return output;
}
/// <summary>
/// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler" /> interface.
/// </summary>
/// <param name="context">An <see cref="T:System.Web.HttpContext" /> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
public void ProcessRequest(HttpContext context)
{
// Set up the response settings
context.Response.ContentType = "image/jpeg";
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.BufferOutput = false;
// مرحله اول
int size = 0;
switch (context.Request.QueryString["Size"])
{
case "S":
size = 100; //100px
break;
case "M":
size = 198; //198px
break;
case "L":
size = 500; //500px
break;
}
byte[] changedImage;
var id = Convert.ToInt32(context.Request.QueryString["PhotoId"]);
byte[] sourceImage = GetImageFromDatabase(id);
// یا
//byte[] sourceImage = GetImageFromDisk(id.ToString(CultureInfo.InvariantCulture));
//مرحله 2
if (size != 0) //غیر از حالت واقعی تصویر
{
changedImage = Helpers.ResizeImageFile(sourceImage, size, ImageFormat.Jpeg);
}
else
{
changedImage = (byte[])sourceImage.Clone();
}
// مرحله 3
if (changedImage == null) return;
context.Response.AddHeader("Content-Length", changedImage.Length.ToString(CultureInfo.InvariantCulture));
context.Response.BinaryWrite(changedImage);
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
در این هندلر ما چند متد اضافه کردیم.
1- متد
GetImageFromDatabase: این متد یک کد تصویر را گرفته و آن را از بانک اطلاعاتی بازیابی میکند. (در صورتی که تصویر در بانک ذخیره شده باشد)
2- متد
GetImageFromDisk: این متد نام تصویر (
با فرض اینکه یک عدد میباشد) را به عنوان پارامتر گرفته و آنرا بازیابی میکند (در صورتی که تصویر در دیسک ذخیره شده باشد.)
3- متد
StreamToByteArray: زمانی که تصویر از فایل خوانده میشود به صورت Stream است این متد یک
Stream را گرفته و تبدیل به یک آرایه بایتی میکند.
در نهایت در متد
ProcessRequestتصویر خوانده شده با توجه به پارامترهای ورودی تغییر اندازه داده شده و در نهایت به خروجی نوشته میشود.
برای استفاده این هندلر، کافی است در توصیر خود به عنوان مسیر رشته ای شبیه زیر وارد نمایید:
PhotoHandler.ashx?PhotoId=10&Size=S
مانند
<img src='PhotoHandler.ashx?PhotoId=10&Size=S' alt='تصویر ازمایشی' />
پ.ن : هرچند میتوانستیم کد هارا بهبود داده و خیلی بهینهتر بنویسیم اما هدف فقط اشنایی با عمل تغییر اندازه تصویر در زمان اجرا بود، امیدوارم اساتید من ببخشن.
نظرات اقای موسوی تا حدودی اعمال شد و در پست تغییراتی انجام شد.
موفق وموید باشید