PDA

View Full Version : کلاسی بری کار با تصاویر آپلود شده در سایت



Javad_Darvish_Amiry
شنبه 07 اسفند 1389, 01:27 صبح
سلام خسته نباشید. نمیدونم مطلبی که آماده کردم چقدر مفید هست، اما چون چند بار دیدم که دوستان با این مسئله مشکل داشتن، این کد رو نوشتم و این جا میزارم. این کلاس، یه کنترل فایل-آپلود و یه عدد صحیح به عنوان عرض تصاویر تامب میگیره، عکس رو از کنترل خونده و توی شیئ Image قرار میده، و همزمان آرایه عکس رو هم آماده میکنه (برای ذخیره تصاویر در دیتابیس مفیده) از طرفی یه تصویر تمب متناسب با عرض وارد شده هم میشازه و تامب رو هم به دو شکل آرایه و Image در دسترس قرار میده. کار کردن باهاش خیلی ساده است. سعی کردم ساده و مختصر و مفید باشه. امیدوارم به درد بخوره.



namespace Kavand.Core.Utilities {

using System;
using System.Drawing.Imaging;
using System.IO;

/// <summary>
/// کلاسی برای کار با کنترل فایل-آپلود، هنگامی که یک تصویر آپلود می گردد؛
/// </summary>
public class Picture {

/// <summary>
/// ارتفاع تصویر آپلود شده؛ می توان این خاصیت را در بانک ذخیره و یا از آن برای تست ارتفاع مجاز آپلود در سایت استفاده کرد؛
/// </summary>
public Int32 Height { get { return this.FullImage.Size.Height; } }

/// <summary>
/// عرض تصویر آپلود شده؛ می توان این خاصیت را در بانک ذخیره و یا از آن برای تست عرض مجاز آپلود در سایت استفاده کرد؛
/// </summary>
public Int32 Width { get { return this.FullImage.Size.Width; } }

/// <summary>
/// حجم تصویر آپلود شده؛ می توان این خاصیت را در بانک ذخیره و یا از آن برای تست حجم مجاز آپلود در سایت استفاده کرد؛
/// </summary>
public Int64 Size { get; private set; }

/// <summary>
/// ارتفاع تصویر تامب ساخته شده از روی تصویر اصلی
/// </summary>
public Int32 ThumbHeight { get; private set; }

/// <summary>
/// عرض تصویر تامب ساخته شده از روی تصویر اصلی
/// </summary>
public Int32 ThumbWidth { get; private set; }

/// <summary>
/// حجم تصویر تامب ساخته شده از روی تصویر اصلی
/// </summary>
public Int64 ThumbSize { get; private set; }

/// <summary>
/// تصویر آپلود شده اصلی
/// </summary>
public System.Drawing.Image FullImage { get; private set; }

/// <summary>
/// تامب ساخته شده از روی تصویر اصلی
/// </summary>
public System.Drawing.Image ThumbImage { get; private set; }

/// <summary>
/// تصویر اصلی آپلود شده به صورت آرایه ای از بایت ها؛ این خاصیت زمانی مفید است که قصد ذخیره تصاویر در بانک را داریم؛
/// </summary>
public Byte[] ImageByte { get; private set; }

/// <summary>
/// تامب ساخته شده از روی تصویر اصلی به صورت آرایه ای از بایت ها؛ این خاصیت زمانی مفید است که قصد ذخیره تصاویر در بانک را داریم؛
/// </summary>
public Byte[] ThumbByte { get; private set; }

/// <summary>
/// فرمت فایل
/// </summary>
public System.Drawing.Imaging.ImageFormat Format { get; private set; }

/// <summary>
/// پسوند فایل آپلود شده
/// </summary>
public String Extension { get; private set; }

/// <summary>
/// یک نمونه از کلاس پیکچر را ساخته، تصویر تامب را محاسبه کرده و خصوصیات را مقداردهی می کند؛
/// </summary>
/// <param name="fileUpload">کنترل فایل-آپلود که فایل آپلود شده توسط آن باید توسط این کلاس پردازش شده و تصویر تامب از آن ساخته شود؛</param>
/// <param name="thumbWidth">عرض مورد نظر برای تصویر تامب که بایستی از روی تصویر اصلی آپلود شده ساخته شود؛</param>
public Picture(System.Web.UI.WebControls.FileUpload fileUpload, Int32 thumbWidth) {

// پسوند فایل آپلود شده را به دست می آورد؛
this.Extension = GetExtension(fileUpload.PostedFile.FileName);

this.FullImage = default(System.Drawing.Image);

// به استریم ورودی نیاز داریم تا از روی آن تصویر را ساخته و یا آن را در آرایه برای ذخیره در بانک بنویسیم
System.IO.Stream stream = fileUpload.PostedFile.InputStream;

try {
// استریم ورودی را در شیئ ایمیج میریزیم؛
// از آن جا که ممکن است کاربر نهایی، فایلی غیر از فایل تصویر آپلود کند، لذا عملیات را در بلاک ترای قرار می دهیم؛
this.FullImage = System.Drawing.Image.FromStream(stream);
} catch (Exception ex) {
// منطق مورد نظر برای کنترل خطا را بنویسید؛
}

this.Size=fileUpload.PostedFile.InputStream.Length ;

this.ImageByte = new Byte[this.Size];
stream.Position = 0;

// استریم ورودی را در آرایه می ریزیم
stream.Read(this.ImageByte, 0, Convert.ToInt32(stream.Length));

stream.Dispose();

this.ThumbWidth = thumbWidth;

// ارتفاع تصویر تامب را از روی ارتفاع و عرض تصویر فعلی با توجه به عرض تعریف شده برای تصویر تامب به دست می آوریم؛
// به این ترتیب تصاویر تامب با عرض یک سان خواهیم داشت که اولا در گالری تصاویر حالت زیباتری از تصاویر با عرض های متفاوت خواهند داشت
// و ثانیا ارتفاع تصاویر تامب متناسب با تصویر اولیه بوده و حالت زننده ای نخواهد داشت؛
this.ThumbHeight = GetThumbHeight(this.ThumbWidth,this.Width, this.Height);

// در صورتیکه ایجاد تصویر تامب نیاز به توقف داشته باشد، این کال-بک اجرا خواهد شد؛
System.Drawing.Image.GetThumbnailImageAbort cb = new System.Drawing.Image.GetThumbnailImageAbort(Thumbn ailCallback);

// تصویر تامب ایجاد می گردد؛
this.ThumbImage = FullImage.GetThumbnailImage(this.ThumbWidth, this.ThumbHeight, cb, System.IntPtr.Zero);

// به این استریم نیاز داریم تا تصویر تامب را در آن ذخیره و بدین وسیله بتوانیم آنرا در آرایه بریزیم
MemoryStream thumbStream = new MemoryStream();

this.Format = GetImageFormat(this.Extension);

// تصور تامب را در استریم میریزیم؛
this.ThumbImage.Save(thumbStream, this.Format);

this.ThumbSize = thumbStream.Length;
this.ThumbByte = new Byte[this.ThumbSize];
thumbStream.Position = 0;
// استریم تامب را در آرایه میریزیم
thumbStream.Read(this.ThumbByte, 0, Convert.ToInt32(thumbStream.Length));
thumbStream.Dispose();
}

/// <summary>
/// پسوند فایل را بر میگرداند
/// </summary>
/// <param name="strPath">رشته ای که حاوی نام فایل است</param>
static public String GetExtension(System.String strPath) {
return System.IO.Path.GetExtension(strPath);
}

/// <summary>
/// فایل فرمت متناسب با پسوند را بر می گرداند
/// </summary>
/// <param name="extension">پسوند مورد نظر</param>
static public ImageFormat GetImageFormat(String extension) {
switch (extension.ToLower()) {
case ".jpg":
case ".jpeg":
case ".jpe":
return ImageFormat.Jpeg;
case ".png":
return ImageFormat.Png;
case ".gif":
return ImageFormat.Gif;
case ".bmp":
return ImageFormat.Bmp;
default:
throw new NotSupportedException();
}
}

/// <summary>
/// از روی ارتفاع و عرض تصویر اصلی، و با توجه به عرض تعریف شده برای تصاویر تامب، ارتفاع تصویر تامب را به دست می آورد
/// </summary>
/// <param name="thumbWidth">عرض تعریف شده برای تصاویر تامب</param>
/// <param name="iWidth">عرض تصویر اصلی</param>
/// <param name="iHeight">ارتفاع تصویر اصلی</param>
static private Int32 GetThumbHeight(Int32 thumbWidth, Int32 iWidth, Int32 iHeight) {
double percent = (Double)iWidth / thumbWidth;
return (Int32)Math.Round((iHeight / percent));
}

/// <summary>
/// در صورتیکه ایجاد تصویر تامب نیاز به توقف داشته باشد، این کال-بک اجرا خواهد شد؛
/// در واقع اگر این متود ترو را بر گرداند عملیات پردازش تصویر برای ساخت تامب متوقف می شود؛
/// </summary>
static private Boolean ThumbnailCallback() {
return false;
}

}
}


موفق باشید.

actros
شنبه 07 اسفند 1389, 03:26 صبح
سلام خسته نباشید. نمیدونم مطلبی که آماده کردم چقدر مفید هست، اما چون چند بار دیدم که دوستان با این مسئله مشکل داشتن، این کد رو نوشتم و این جا میزارم. این کلاس، یه کنترل فایل-آپلود و یه عدد صحیح به عنوان عرض تصاویر تامب میگیره، عکس رو از کنترل خونده و توی شیئ Image قرار میده، و همزمان آرایه عکس رو هم آماده میکنه (برای ذخیره تصاویر در دیتابیس مفیده) از طرفی یه تصویر تمب متناسب با عرض وارد شده هم میشازه و تامب رو هم به دو شکل آرایه و Image در دسترس قرار میده. کار کردن باهاش خیلی ساده است. سعی کردم ساده و مختصر و مفید باشه. امیدوارم به درد بخوره.
موفق باشید.

دست درد نکنه جواد جان.
اتفاقا من هم یه چنین چیزی رو تو در غالب یه User Control نوشتم :
عکس و لوگو (لوگو اختیاری) می گیره و لوگو رو به عکس اصلی اضافه می کنه و یه تامبنیل با سایز دلخواه (و با حجم کم) تحویل میده :دی
ولی یه خورده دیگه کار داره.
باز هم از این مطالب بذار

jaykob
سه شنبه 31 خرداد 1390, 16:55 عصر
سلام

بعد از استفاده از این کلاس و بازسازی اون به چه شکل می تونیم thumb ایجاد شده را داخل یک پوشه ذخیره کنیم ؟

Javad_Darvish_Amiry
پنج شنبه 13 مرداد 1390, 19:14 عصر
@jaykob (http://barnamenevis.org/member.php?133240-jaykob)
سلام ببخشید که دیر شد. هم سرم خیلی شلوغ بود و هم بقیه اش رو هم که میدونی. برای ذخیره، میتونی به راحتی از اشیاء Image بدست اومده، متود Save رو فراخونی کنی. یه مسیر بهش میدی و فایل اونجا ذخیره میشه. مثلا تصویر اصلی رو میخوام در پوشه Uploads/Images و تامب رو در پوشه Uploads/Tuhmbs ذخیره کنم. کافیه مسیر کامل رو تعیین کنی: var fullImagePath = HttpContext.Current.Server.MapPath(~/Uploads/Images); // save the full image here وبعد متود Save رو به شکل زیر صدا بزنی:

var fullImagePath = HttpContext.Current.Server.MapPath(~/Uploads/Images/a_name_to_your_image.your_images_extension); // save the full image here
this.FullImage.Save(fullImagePath, this.ImageFormat);

و به همین ترتیب میتونی تامب رو هم ذخیره کنی.
البته با آرایه بایتی هم که بدست آوردی و با FileStream هم میتونی ذخیره سازی رو انجام بدی. ولی چون خود اشیاء Image هم از تامب و هم از عکس اصلی موجودند، روش اول راحت تره (در هر صورت، با FileStream ذخیره میشه؛ ولی متود Save که بالا گفتم، تو شیئ Image کار با استریم فایل رو کپسوله کرده برات). بازم شرمنده که دیر شد. زنده باشی.

ali_mnkt
جمعه 14 مرداد 1390, 09:20 صبح
با سلام
اگه یک مثال بذاری خیلی عالی می شه

Javad_Darvish_Amiry
جمعه 14 مرداد 1390, 20:32 عصر
:لبخندساده:
متوجه نمیشم مثال از چی؟ یه نمونه از کلاس بسازید و متود Save رو همونطوری که بالا گفتم فراخونی کنید.
مثال کاملتر:
فرض کنید یه کنترل فایل آپلود به اسم fu1 رو صفحه داریم و میخوایم بعد از کلیک یه دکمه ای رو صفحه، تصویری که آپلود شده روی سیستم فایل ذخیره کنیم؛


var maxWidth = 800;
var mahHeight = 1200;
var thumbWith = 200;
var maxSize = 1 * 1024 * 1024; // 1mb | 1000 kb | 1000000 b

if(fu1.HasFile){
try{
var pic = new Picture(fu1, thumbwidth);

if(isNotAllowed(pic.Extension))
// throw an exception or show a message to end-user!!!
// isNotAllowed is a method that checks the extension is allowed or not!

if(pic.Width > maxWidth)
// throw an exception or show a message to end-user!!!

if(pic.Height > maxHeight)
// throw an exception or show a message to end-user!!!

if(pic.Size > maxSize)
// throw an exception or show a message to end-user!!!

// the path that you want to save files there
var savepath = Server.MapPath("~/YourUploadsFolder/");

// generate a name for full-image
var filename = "some-name-you-want-for-example-can-take-it-as-a-rondom-string" + pic.Extension;

// generate a name for thumbnail
var thumbname = "a-name-for-thumb-image" + pic.Extension;

// saves the full-image
pic.FullImage.Save(Path.Combine(savepath, filename), this.ImageFormat);

// saves the thumbnail
pic.ThumbImage.Save(Path.Combine(savepath, thumbname), this.ImageFormat);

} catch(Exception ex){
// throw an exception or show a message to end-user!!!
}
}

ali_mnkt
شنبه 15 مرداد 1390, 00:10 صبح
اگه من بخوام کاربر چند عکس را مثلا برای یک خبر ، انتخاب کنه (با یک file upload) و با هم upload کنه می شه از این کلاس استفاده استفاده کرد ؟

Javad_Darvish_Amiry
شنبه 15 مرداد 1390, 00:55 صبح
من تو ASP.NET سنتی این کارو نکردم. اما میدونم که توی شیئ Request یه آبجکت به اسم Files داری که یه نوع HttpFileCollection برمیگردونه. توی MVC از همین مسیر کالکشنم رو گرفتم (البته تو MVC از نوع HttpFileCollectionBase هست) و مشکلی نداشت. تو ASP.NET باید تست کنی. ولی اگه بتونی کالکشن رو دریافت کنی، برای استفاده از کلاس بالا مشکلی نداری. چون با یه foreach میتونی تو کالکشن حرکت کنی و به ازای هر فایل که تو کالکشن داری یه نمونه از شیئ Picture بسازی و کارای بالا رو روش انجام بدی. - توضیح: من با MVC3 تست کردم و MVC3 با HTML5 خیلی سازگار شده، و تو HTML5 تگ input-file خاصیت multiselect داره که همزمان چندین فایل رو انتخاب و به سرور پست میکنه. اما تو xhtml و html4 اینطوری نبود. تا اونجایی که من یادمه کنترل های مولتی سلکت فایل ها، به ازای هر فایلی که اد میکردی به لیست (سمت کلاینت) با جاوااسکریپت یه input-file میساختن و وقتی به سرور پست میشد، در واقع چندین فیلد اینپوت فایل وجود داشت. حالا این تفاوت تو عمل چه تاثیری توی دریافت فایل داره، باید تست کنی. چون من هیچوقت پروژه ای نداشتم که همچین نیازمندی داشته باشه؛ ولی این توضیحات ربطی به سوال شما نداشت و جواب سوال شما همونیه که عرض کردم: بله مشکلی نداره، به ازای هر فایلی که به سرور میرسه یه نمونه از کلاس بساز و بقیه... - - توضیح2: این کلاس، برشی از یه کلاس خیلی بزرگ تو یکی از پروژه هامه که همینطور که میبینی، حتی آرایه ی بایتی فایل های پست شده رو هم بر میگردونم. چون تو اون پروژه من فایل ها رو روی سیستم فایل ذخیره نمیکردم و میریختمشون تو دیتابیس. میتونید این بخش ها رو حذف کنید تا کلاس سبکتر و چابکتری بدست بیارید (به عهده خودتون)؛ ضمنا اگه رو MVC کار میکنید، کلاس بالا رو برای استفاده از MVC تغییر دادم و خاصیت های مولتی سلکت و ModelState و ساختن اسم برای فایل و ... هم توش وجود داره و خیلی کامل تر و البته چالاک تر از کلاس بالاست. اگه خواستین این گوگل پلاس منه: Javad Darvish Amiry اد کنید یا میل بزنید براتون بفرستم. - پاینده باشید.