PDA

View Full Version : خطا در تبدیل image به byte



hamid_hr
دوشنبه 19 خرداد 1393, 16:05 عصر
سلام
این تابعو برا تبدیل image به byte[] نوشتم

public byte[] imageToByteArray(System.Drawing.Image imageIn, System.Drawing.Imaging.ImageFormat ImgFormat)
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
imageIn.Save(ms, ImgFormat);
return ms.ToArray();
}
}


حالا تو خط image in.save این خطا رو میده
A generic error occurred in GDI+.

لطفا راهنمایی کنین

__H2__
دوشنبه 19 خرداد 1393, 19:36 عصر
سلام
مشکل در جایی است که imageIn را نمونه سازی کرده اید.
در صورت عدم حل مشکل دستورات محل پر شدن و نمونه سازی imageIn را قرار دهید.
موفق باشید.

hamid_hr
سه شنبه 20 خرداد 1393, 08:59 صبح
خب من یه pictuerBox دارم که imagein رو اینطوری پر میکنم
imagein = pic1.Image;
این pictuerBoxهم از دو طریق پر میشه
یه دکمه بارگذاری داری و عکس رو با یک openfiledialog باز میکنم و میارم تو pictuerBox نشون میدم
روش دوم اینه که از طریق دریتا بیس پرش میکنم

وقتی از روش اول بارگذاری میشه مشکلی نداره ولی وقتی از روش دوم عکسو بارگذاری میکنم مشکل پیش میاد

__H2__
سه شنبه 20 خرداد 1393, 18:23 عصر
سلام
همانطور که گفتم منظورم محل نمونه سازی و ساخته شدن بوده است.
اگر هم دقت کنید میبینید که با یک روش که تصویر را پر میکنید مشکلی ندارید ولی در روش دیگر مشکل رخ میدهد، این تایید کننده همان نکته است که خدمت تان عرض کردم، مشکل از محل تولید است.
شما کدهای پر کردن تصویر از روش دوم تان را اینجا قرار دهید.

مثلاً خطای رایجی که الآن به ذهنم میرسد آن است که زمان ساخت تصویر هم طبیعتاً یک stream استفاده کرده اید؟! احیناً احتمالاً بعد از ساخت تصویر Dispose اش که نکرده اید؟؟؟

hamid_hr
سه شنبه 20 خرداد 1393, 19:23 عصر
از دیتابیس میخونم بعد با یک تابع تبدیل به image میکنم بعد pictuerbox رو پر میکنم
اینم تابع


public System.Drawing.Image byteArrayToImage(byte[] byteArrayIn)
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream(byteArrayIn))
{
return System.Drawing.Image.FromStream(ms);
}
}

__H2__
سه شنبه 20 خرداد 1393, 23:48 عصر
سلام
چه حدس جالبی... حدس میزنم مشکل همان است.
این کد را امتحان کنید:

public System.Drawing.Image byteArrayToImage(byte[] byteArrayIn)
{
var ms = new System.IO.MemoryStream(byteArrayIn);
return System.Drawing.Image.FromStream(ms);
}

البته امیدوارم که این باعث نشود که در استفاده از using مردد شوید، استفاده از این دستور بسیار عادت خوب و مفیدی است ولی اینجا بهتر است استفاده نشود.

hamid_hr
پنج شنبه 22 خرداد 1393, 19:32 عصر
اره درست شد
ولی خب چرا؟
میشه دلیل این خطا رو بگید
خب فک کنید من تعداد زیادی عکسو اینطوری تبدیل کنم نمیخواد منابع مربوط به memoryStream اونها ازاد بشن؟

plus
جمعه 23 خرداد 1393, 07:45 صبح
سلام
چه حدس جالبی... حدس میزنم مشکل همان است.
این کد را امتحان کنید:

public System.Drawing.Image byteArrayToImage(byte[] byteArrayIn)
{
var ms = new System.IO.MemoryStream(byteArrayIn);
return System.Drawing.Image.FromStream(ms);
}

البته امیدوارم که این باعث نشود که در استفاده از using مردد شوید، استفاده از این دستور بسیار عادت خوب و مفیدی است ولی اینجا بهتر است استفاده نشود.

خیلی بعیده که خطای دوستمون مربوط به این قضیه باشه.من همیشه بعد از لود تصویر از هر Stream ی، چه MemoryStream چه FileStream، اون Stream رو میبندم و مشکلی پیش نمیاد.منطقا هم بعد از اینکه تصویر لود بشه اون تصویر هیچ وابستگی ای به Stream نداره.

Hadoop
جمعه 23 خرداد 1393, 08:25 صبح
using(var memoryStream = new MemoryStream())
{
sourceStream.CopyTo(memoryStream);
return memoryStream.ToArray();
}

__H2__
جمعه 23 خرداد 1393, 13:23 عصر
سلام


ولی خب چرا؟

بنظر میرسد فرآیند ذخیره سازی نیاز به اطلاعات اضافه از منبع اولیه دارد و اگر این منبع Dispose شده باشد فرآیند مذکور به خطا خواهد خورد.



خب فک کنید من تعداد زیادی عکسو اینطوری تبدیل کنم نمیخواد منابع مربوط به memoryStream اونها ازاد بشن؟

بطور خاص منبع کلاس MemoryStream یک آرایه باینری است و با Close و Dispose آزاد سازی نمیشود.
آزاد سازی واقعی این کلاس فقط توسط جمع آوری کننده حافظه هرز دات نت رخ خواهد داد و تا وقتی اشاره گری به MemoryStream وجود دارد آزاد سازی واقعی رخ نخواهد داد در این کلاس خاص شما فقط با Dispose ورودی خروجی و دسترسی و... را خواهید بست ولی فضای RAM تا null شدن تمام اشاره گر ها باقی خواهد ماند.
دقت کنید که در هر شرایطی حداقل اشاره گری به این کلاس درون کلاس تصویر وجود خواهد داشت و زنده خواهد ماند!



خیلی بعیده که خطای دوستمون مربوط به این قضیه باشه.من همیشه بعد از لود تصویر از هر Stream ی، چه MemoryStream چه FileStream، اون Stream رو میبندم و مشکلی پیش نمیاد

و دستور Save هم استفاده کرده اید؟! امتحانش ضرر ندارد!

موفق باشید.

mehdi.mousavi
جمعه 23 خرداد 1393, 15:39 عصر
سلام.
آیا به این مساله دقت کرده اید که کلاس Image، در واقع یک abstract class هستش؟ پس Image.FromStream چطوری میتونه یک Image برگردونه، در حالیکه Image فقط یک abstract class ای هستش که نمیشه Instantiate اش کرد؟ خوب، واضحه. فقط در یک صورت چنین امکانی وجود داره و اونم این هستش که متود مزبور حتما داره Instance ای از کلاسی میسازه که از Image درایو شده که فقط در این صورت هستش که میتونه مقدار بازگشی رو به Image کست کنه و اونو از طریق FromStream برگردونه. حالا سوال تغییر میکنه: "این چه کلاسی هستش که FromStream درون خودش Instantiate میکنه و با استفاده از اون Image رو به ما برمیگردونه؟"

این کلاس، کلاس Bitmap (http://msdn.microsoft.com/en-us/library/z7ha67kw.aspx) هستش. کلاسی که از Image درایو شده، و در درون Image.FromStream در حقیقت داره Instantiate میشه. در حقیقت در کلاس Image، متودی با Signature زیر وجود داره که این کارو در درون خودش انجام میده:

internal static Image CreateImageObject(IntPtr nativeImage);

در درون این متود، جایی Bitmap.FromGDIplus فراخوانی میشه، متودی که Instance ای از کلاس Bitmap (بر اساس native image ای که بعنوان formal parameter بهش داده شده) میسازه. اما دونستن این مطالب چه کمکی به دلیل پی بردن به اون خطا میکنه؟ پاسخ اینجاست که اگر به مستندات کلاس Bitmap (http://msdn.microsoft.com/en-us/library/z7ha67kw.aspx) توجه کنید، اولین خط در بخش Remark نوشته شده که "شما باید stream را در طول حیات Bitmap، باز نگه دارید". درسته شده دارید یک Image Instance از متود Image.FromStream میگیرید، اما اون Instance توسط Bitmap.FromGDIplus ایجاد میشه و Bitmap کلاسی هستش که داره Instantiate میشه. در حقیقت اینجا شما دارید "مالکیت" اون stream ر به Bitmap واگذار می کنید، پس اجازه ندارید تا مادامیکه کلاس Bitmap در حافظه هستش اون Stream رو از بین ببریبد. حالا با این توضیحات، میتونیم به این سوال شما پاسخ بدیم:


خب فک کنید من تعداد زیادی عکسو اینطوری تبدیل کنم نمیخواد منابع مربوط به memoryStream اونها ازاد بشن؟
کافیه تا Image دریافت شده رو Dispose کنید. بدین ترتیب Image به نوبه خودش Stream مربوطه رو آزاد خواهد کرد. (چون باز هم تکرار میکنم، مالکیت Stream در حال حاضر در اختیار Image قرار گرفته).

موفق باشید.

plus
جمعه 23 خرداد 1393, 16:26 عصر
و دستور Save هم استفاده کرده اید؟! امتحانش ضرر ندارد!
موفق باشید.
جالبه، شما درست میگین...هرچند این رفتار Image بنظر مسخره میاد...