View Full Version : دسترسی به Bitmap با Pointer
JalaliMehr
دوشنبه 15 شهریور 1389, 13:57 عصر
سلام.
تو VC++ برای اینکه محتوای یک Bitmap از GetPixel و SetPixel استفاده نکنم و از Pointer استفاده کنم .چیکار بایستی انجام بدم.
-------------------------------------------------------
اگر حوصله مثال زدن ندارید یک لینک به من معرفی کنید. میخام با pointer رو RGB حرکت کنم و دستکاریش کنم. مثلاً uchar *p و سپس با P دستکاریش کنم.
mehdi.mousavi
چهارشنبه 17 شهریور 1389, 11:05 صبح
سلام.
تو VC++ برای اینکه محتوای یک Bitmap از GetPixel و SetPixel استفاده نکنم و از Pointer استفاده کنم .چیکار بایستی انجام بدم.
-------------------------------------------------------
اگر حوصله مثال زدن ندارید یک لینک به من معرفی کنید. میخام با pointer رو RGB حرکت کنم و دستکاریش کنم. مثلاً uchar *p و سپس با P دستکاریش کنم.
سلام.
می تونید از CBitmap::GetBitmapBits (http://msdn.microsoft.com/en-us/library/zy0022z9%28VS.80%29.aspx) و CBitmap::SetBitmapBits (http://msdn.microsoft.com/en-us/library/02a868df%28VS.80%29.aspx) استفاده کنید.
بعنوان مثال، این کد (http://www.codeguru.com/forum/showpost.php?p=352653&postcount=3) با استفاده از این دو متود، تصویر رو به GrayScale تبدیل میکنه.
موفق باشید.
مصطفی ساتکی
چهارشنبه 17 شهریور 1389, 14:31 عصر
البته در اون مثالی که آورده شده حافظه مجدد اختصاص داده شده و مجدداً با صفر پر شده که خودش یه سرباره.
شما زمانیکه GetBitmap می کنید به اطلاعات Bitmap از جمله اشاره گر به ابتدای bitmap رو دسترسی دارین.
تابع GrayScale رو براتون با یه روش دیگه مثال زدم.
void Grayscale(CBitmap& bmp)
{
BITMAP bmpinfo;
bmp.GetBitmap(&bmpinfo);
int i, j;
BYTE *p = (BYTE*) bmpinfo.bmBits;
BYTE gray;
for (i =0;i< bmpinfo.bmHeight;i++)
for (j=0;j<bmpinfo.bmWidth;j++)
{
gray = BYTE(0.56*p[2]+ 0.33*p[1]+0.11*p[0]);
p[0] = gray;
p[1] = gray;
p[2] = gray;
p += 3;
}
}
void Ctest31Dlg::OnBnClickedOk()
{
CFileDialog dlg(TRUE);
if (dlg.DoModal() == IDOK)
{
HBITMAP hbit = (HBITMAP) ::LoadImage(AfxGetInstanceHandle(),dlg.GetPathName (),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION | LR_LOADFROMFILE);
CBitmap bmp;
bmp.Attach(hbit);
Grayscale(bmp);
BITMAP bmpinfo;
bmp.GetBitmap(&bmpinfo);
CClientDC dc(this);
HDC memdc = CreateCompatibleDC(dc);
SelectObject(memdc,bmp);
BitBlt(dc.GetSafeHdc(), 0,0,bmpinfo.bmWidth,bmpinfo.bmHeight,memdc,0,0,SRC COPY);
DeleteObject(hbit);
DeleteDC(memdc);
bmp.DeleteObject();
}
}
mehdi.mousavi
چهارشنبه 17 شهریور 1389, 15:10 عصر
@Delphi_CAT:
سلام.
از اونجاییکه hbit رو دارید به یک CBitmap متصل می کنید، دیگه نباید DeleteObject(hbit) رو Call کنید. ضمنا، bmp.DeleteObject() هم در کد شما باید حذف بشه، زیرا Destructor کلاس CBitmap خودش GDI Resource مربوطه رو (هنگام خارج شدن متغیر bmp از Scope) آزاد میکنه.
موفق باشید.
مصطفی ساتکی
پنج شنبه 18 شهریور 1389, 06:54 صبح
از اونجاییکه hbit رو دارید به یک CBitmap متصل می کنید، دیگه نباید DeleteObject(hbit) رو Call کنید. ضمنا، bmp.DeleteObject() هم در کد شما باید حذف بشه، زیرا Destructor کلاس CBitmap خودش GDI Resource مربوطه رو (هنگام خارج شدن متغیر bmp از Scope) آزاد میکنه.سلام.نکته ای که شما فرمودید کاملاً صحیحه .من همیشه منابع رو از هر جایی که استفادم تموم بشه آزاد می کنم .این یه عادت شده.
mehdi.mousavi
پنج شنبه 18 شهریور 1389, 10:21 صبح
سلام.
این عادت، عادت بسیار خوبی هستش، اما به شرطیکه دست و پا گیر نشه. از اونجاییکه برنامه نویسها عموما فراموش میکردن که Resource ها رو آزاد کنن، و این آزاد سازی Resource ها میتونه در Branch های مختلف کد صورت بگیره و باعث کثیف شدن (و پایین آوردن خوانایی) کد بشه، عموما عملا آزاد سازی Resource ها رو در Destructor کلاس انجام میدن.
اما در مورد کدی که شما نوشتید. ببینید. کد شما در واقع ایراد داره. شما ابتدا دارید DeleteObject(hbit); رو Call میکنید. این باعث میشه تا Resource مربوطه به System برگرده. اما دو خط بعدش، دارید bmp.DeleteObject رو Call میکنید. الان، حافظه گرفته شده توسط GDI Resource نسبت داده شده به hbit آزاد شده، اما شما دارید مجددا bmp.DeleteObject رو Call میکنید که در واقع داره CGdiObject::DeleteObject رو Call میکنه. خود این تابع چطور نوشته شده؟
BOOL CGdiObject::DeleteObject()
{
if (m_hObject == NULL)
return FALSE;
return ::DeleteObject(Detach());
}
در واقع ابتدا نگاه میکنه ببینه m_hObject درونی NULL هستش یا نه. اگر بود، دیگه میدونه Resource ای برای آزاد سازی وجود نداره و مقدار FALSE رو برمیگردونه.
برای کد شما، این متغیر NULL نیست، اگر چه، شما یکبار قبلا Resource رو به سیستم برگردونده اید. پس، ابتدا Detach رو Call میکنه، که این خودش، باعث میشه m_hObject برابر NULL بشه. بعد، برای بار دوم، DeleteObject داره روی همون hbit ای که قبلا آزاد شده بود، Call میشه. (که خوب، این مساله نباید رخ میداد).
در نهایت، وقتی bmp از Scope خارج میشه، Destructor کلاس مربوطه Call میشه. در مخرب CGdiObject، داره DeleteObject ای که کدش رو بالا گذاشتم مجددا Call میشه. اما اینبار، m_hObject اش NULL هست، چون دفعه قبل، Detach رو فراخوانی کرده بود. پس اینبار اتفاق خاصی نخواهد افتاد.
بنابراین، بهتره همواره کار آزادسازی Resource ها رو (در صورت امکان) به Destructor کلاسها بسپرید، تا کدتون خوانا و امن باشه. کد شما یه ایراد دیگه هم داره، و اون، عدم Check کردن مقادیر بازگشتی توابع هستش. همینطور اگر Exception ای در کد شما رخ بده، کد شما هرگز نمیتونه تضمین کنه که DeleteObject ای که نوشته اید فراخوانی میشه (مگر اینکه از try/finally استفاده کنید که بازهم، کد پیچیده و ناخوانا میشه)، اما سیستم همواره تضمین میکنه، که اگر متغیر شما، به هر دلیلی (اعم از Exception و ...) از Scope خارج شد، Destructor اش Call بشه و اونجا هم Resource های گرفته شده به سیستم برگردونده بشه.
موفق باشید.
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.