تغییر اندازه تصاویر #1
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: چهار دقیقه

برای برنامه نویسان همیشه این امکان هست که تصاویری را که از کاربر دریافت می‌کنند تغییر اندازه دهند، مثلا در همین سایت تصاویری از کاربران جهت نمایش در پروفایل آنها دریافت می‌شود، در همین سایت نیز این اتفاق می‌افتد مثلا تصاویر پروفایل کاربران با اندازه‌های متفاوتی نشان داده می‌شود.

برای انجام این کارها میتوان به دو طریق عمل کرد:
  1. تغییر اندازه تصویر در زمان ذخیره‌سازی
  2. در زمانی که می‌خواهیم تصویر را به بازدید کننده نشان دهیم
در حالت 1 زمانی که تصویری را از کاربر دریافت می‌کنیم با توجه به اینکه تصویر را با چه اندازه‌هایی در نرم افزار نیاز داریم تغییر اندازه داده و تک تک ذخیره می‌کنیم، این روش کل عملیات در زمان ثبت و تنها یکبار اتفاق می‌افتد، این روش جای بیشتری از منابع (مانند هارد دیسک یا دیتابیس) سرور را اشغال می‌کند اما در عوض می‌توان گفت سرعت بالاتری دارد، در روش دوم زمانی که بازدید کننده از سایت (نرم افزار) بازدید می‌کند تصویر اصلی با توجه به نیاز تغییر اندازه داده شده و برای کاربر ارسال می‌شود (در واقع کاربر آن را مشاهده می‌کند)، این روش فضای کمتری از منابع را اشغال می‌کند اما در زمان اجرا عملیات اضافی برای هر کاربری (البته با کش کردن این عملیات کم می‌شود) انجام می‌شود.
در هر دو روش گفته شده در هر صورت ما باید متد (توابعی) برای تغییر اندازه تصویر داشته باشیم که در زیر نحوه نوشتن آن را شرح خواهیم داد.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace PWS
{
    public static class Helpers
    {
        /// <summary>
        /// تغییر اندازه تصویر
        /// </summary>
        /// <param name="imageFile">آرایه بایتی از تصویر مورد نظر</param>
        /// <param name="targetSize">اندازه تصویر خروجی</param>
        /// <param name="format">فرمت تصویر خروجی</param>
        /// <returns></returns>
        public static byte[] ResizeImageFile(this byte[] imageFile, Int32 targetSize, ImageFormat format)
        {
            if (imageFile == null)
                throw new Exception("لطفا تصویر اصلی را مشخص نمایید");
            //باز کردن تصویر اصلی به عنوان یک جریان
            using (var oldImage = Image.FromStream(new MemoryStream(imageFile)))
            {
                //محاسبه اندازه تصویر خروجی با توجه به اندازه داده شده
                var newSize = CalculateDimensions(oldImage.Size, targetSize);
                //ایجاد تصویر جدید
                using (var newImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format24bppRgb))
                {
                    using (var canvas = Graphics.FromImage(newImage))
                    {
                        canvas.SmoothingMode = SmoothingMode.AntiAlias;
                        canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
                        //تغییر اندازه تصویر اصلی و قرار دادن آن در تصویر جدید
                        canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
                        var m = new MemoryStream();
                        //ذخیره تصویر جدید با فرمت وارد شده
                        newImage.Save(m, format);
                        return m.GetBuffer();
                    }
                }
            }
        }

        /// <summary>
        /// محاسبه ابعاد تصویر خروجی
        /// </summary>
        /// <param name="oldSize">اندازه تصویر اصلی</param>
        /// <param name="targetSize">اندازه تصویر خروجی</param>
        /// <returns></returns>
        private static Size CalculateDimensions(Size oldSize, Int32 targetSize)
        {
            var newSize = new Size();
            if (oldSize.Height > oldSize.Width)
            {
                newSize.Width = Convert.ToInt32(oldSize.Width * (targetSize / (float)oldSize.Height));
                newSize.Height = targetSize;
            }
            else
            {
                newSize.Width = targetSize;
                newSize.Height = Convert.ToInt32(oldSize.Height * (targetSize / (float)oldSize.Width));
            }
            return newSize;
        }
    }
}

  1. در متد ResizeImageFileتصویر اصلی به عنوان یک جریان باز می‌شود. (سطر 23)
  2. اندازه تصویر خروجی با توجه به اندازه وارد شده توسط متد CalculateDimensions تعیین می‌شود؛ روال کار متد CalculateDimensions اینگونه است که اندازه عرض و ارتفاع تصویر اصلی بررسی می‌شود و با توجه به اینکه کدام یک از اینها بزرگتر است تغییر اندازه در آن صورت می‌گیرد، مثلا در صورتی که عکس ارتفاع بیشتری نسبت به عرض تصویر داشته باشد تصویر تغییر اندازه داده شده نیز با توجه به تناسب ارتفاع تغییر داده می‌شود و بالعکس. (سطر 26)
  3. پس از تغییر اندازه تصویر جدیدی در حافظه ایجاد می‌شود. (سطر 28)
  4. سپس تنظیمات گرافیکی لازم بروی تصویر جدید اعمال می‌شود. (سطر 30 تا 34)
  5. تصویر اصلی با توجه به اندازه جدید تغییر کرده و در تصویر جدید قرار می‌گیرد. (سطر 36)
  6. در نهایت تصویر جدید با فرمت وارد شده در متد ذخیره شده و به عنوان خروجی متد برگشت داده می‌شود. (سطر 37 تا 40)
خروجی این متد نیز آرایه بایتی می‌باشد که به سادگی می‌توانید از آن برای ذخیره تصاویر در دیتابیس استفاده نمایید.

نحوه استفاده از این تابع در ASP.NET می‌تواند به صورت زیر باشد :
byte[] oldImage = FileUploadImage.FileBytes;
byte[] target = oldImage.ResizeImageFile(100, ImageFormat.Jpeg);
در واقع فراخوانی مذکور تصویر ورودی را به اندازه 100 پیکسل تغییر داده و در ارایه بایتی به نام target ذخیره می‌کند.
در بخش بعد در زمان نمایش تصویر به کاربر آن را تغییر اندازه خواهیم داد.
لازم به ذکر است که کد‌های تغییر اندازه از StarterKit‌های میکروسافت کپی‌برداری شده است.
  • #
    ‫۱۱ سال و ۱۱ ماه قبل، سه‌شنبه ۱۴ آذر ۱۳۹۱، ساعت ۱۶:۵۴
    بسیار عالی

    در asp.net MVC کلاس webImage در فضانام System.Web.Helpers این امکانات رو در اختیار توسعه دهنده قرار میده .
    • #
      ‫۱۱ سال و ۱۱ ماه قبل، سه‌شنبه ۱۴ آذر ۱۳۹۱، ساعت ۱۸:۳۰
      بله دیدم جالب بود واسم، اما تغییر اندازه ندیدم کدوم متده؟
  • #
    ‫۱۰ سال و ۵ ماه قبل، شنبه ۲۷ اردیبهشت ۱۳۹۳، ساعت ۱۹:۰۶
    لطفا در مورد اینکه در زمان واکشی تصاویر از دیتابیس (کش کنیم ) توضیح دهید
    چون خیلی سرعت کار با سایت پایین میاد
    مثلا هر بار کاربر که بخواد از صفحه ای به صفحه ای دیگه بره تصاویر از نو بارگزاری میشن و این سرعت سایت رو کند میکنه
  • #
    ‫۱۰ سال و ۲ ماه قبل، جمعه ۳۱ مرداد ۱۳۹۳، ساعت ۲۳:۴۷
    سلام؛ موقع تغییر سایز یک تصویر png به png پس زمینه رو مشکی میکنه. آیا راهی هست در صورتی که تصویر اولیه png باشه  تصویر نهایی هم بدون پس زمینه باشه.
      • #
        ‫۵ سال قبل، یکشنبه ۲۱ مهر ۱۳۹۸، ساعت ۱۹:۰۷
        در مورد تصاویر با فرمت GIF.
        وقتی تغییر اندازه صورت می‌گیرد تصویر متحرک نیست.به نظر فرمت تصویر GIF را به هم می‌ریزد.برای تصاویر GIF  راهی به نظر می‌رسد؟مرسی
        • #
          ‫۵ سال قبل، یکشنبه ۲۱ مهر ۱۳۹۸، ساعت ۱۹:۱۶
          - بهتر است از نمونه‌های مشابه مانند « ImageSharp » و یا « AnimatedGif » استفاده کنید.
          - و یا باید یک حلقه را به ازای هر فریم ایجاد کنید:
          System.Windows.Media.Imaging.GifBitmapEncoder gEnc = new GifBitmapEncoder();
          
          foreach (System.Drawing.Bitmap bmpImage in images)
          {
              var bmp = bmpImage.GetHbitmap();
              var src = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                  bmp,
                  IntPtr.Zero,
                  Int32Rect.Empty,
                  BitmapSizeOptions.FromEmptyOptions());
              gEnc.Frames.Add(BitmapFrame.Create(src));
              DeleteObject(bmp); // recommended, handle memory leak
          }
          using(FileStream fs = new FileStream(path, FileMode.Create))
          {
              gEnc.Save(fs);
          }
  • #
    ‫۹ سال و ۸ ماه قبل، یکشنبه ۳ اسفند ۱۳۹۳، ساعت ۲۲:۵۵
    با تشکر مقاله بسیار خوبی بود.
    ImageResizer  یک کتابخانه متن باز هست که امکانات کاملی ارائه کرده و helper  خوبی هم برای mvc داره