Поиск:

Ответ в темуСоздание новой темы Создание опроса
> После рисования на контексте получить Bitmap, Указатель bmBits оказывается нулевым 
:(
    Опции темы
Dreamer_0x01
Дата 15.8.2007, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



Хочу сделать следующее. Порисовав на контексте в памяти, получить Bitmap полученного художества, сделать что-то с ним что-то (например, выявить светлые и темные области, что-то затемнить, что-то осветлить, короче, нужна прямая работа с байтами битмапа), а потом уже скопировать контекст из памяти в видимый.

Но не получается. Я сделал совместимый с контекстом битмап, выбрал его через SelectObject.
Потом порисовал в контексте. Потом делаю GetBitmap, получаю структуру BITMAP. В ней оказываются заполненными все значения, кроме собственно битмапа - указатель на него равен нулю. Как мне все-таки достать эту последовательность байт?


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Earnest
Дата 16.8.2007, 10:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



GetBitmapBits
НО лучше сразу создать DIB-секцию, подсунуть ее в контекст (так же как подсовывается битмап) и иметь прямой доступ к битам в любой момент, без промежуточного копирования.


--------------------
...
PM   Вверх
Dreamer_0x01
Дата 16.8.2007, 11:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



Earnest, и как я понял, я еще где-то должен выделить память под буфер, который должен подставить в GetBitmapBits ? Получается, это не прямой доступ, и после того, как я надругаюсь над битмапом, я должен сделать обратное копирование SetBitmapBits ?

Цитата

лучше сразу создать DIB-секцию


Что такое DIB - секция?


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Earnest
Дата 16.8.2007, 16:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Цитата(Dreamer_0x01 @  16.8.2007,  12:29 Найти цитируемый пост)
, это не прямой доступ, и после того, как я надругаюсь над битмапом, я должен сделать обратное копирование SetBitmapBits 

Именно. DIB-секция же, в отличие от битмапа, предоставляет прямой доступ к битам.
См. CreateDIBSection



--------------------
...
PM   Вверх
Dreamer_0x01
Дата 17.8.2007, 13:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



Earnest, вроде как получилось, но что-то с цветами полный бардак.

Поставил в полях структуры 32 битный цвет. По идее, такой цвет должен работать с COLORREF.
Но цвета оказались перепутанными. В данном примере я хочу к примеру увеличить интенсивность синего света, но на самом деле увеличивается интенсивность красного цвета. Получается, что с каждым пикселом мне надо работать уже не как с unsigned int, а как с четыремя unsigned char.
Я думал, что интенсивности цветов в каждом пикселе распологаются по порядку: AARRGGBB, но что-то не получается... Вместо усиления синего оттенка усиливается красный.
Вообще, как бы мне "пречесать" мой код, чтобы он правильно работал, и нужно ли после создания "убивать" DIB-секцию, или она "умрет" вместе с деструктором контекста?

Код

void CDIBDlg::OnPaint() 
{
    CRect rect;
    GetClientRect(&rect);
    CPaintDC dcDest(this); // device context for painting

    CDC DCMem;
    DCMem.CreateCompatibleDC(&dcDest);
    VOID *pBits; 
    int w=rect.Width();
    int h=rect.Height(); 
    BITMAPINFO bmi; 
    bmi.bmiHeader.biSize= sizeof(BITMAPINFOHEADER); 
    bmi.bmiHeader.biWidth=w; 
    bmi.bmiHeader.biHeight= h; 
    bmi.bmiHeader.biPlanes=1; 
    bmi.bmiHeader.biBitCount=32; 
    bmi.bmiHeader.biCompression=BI_RGB; 
    bmi.bmiHeader.biSizeImage=0; 
    bmi.bmiHeader.biClrUsed=0; 
    bmi.bmiHeader.biClrImportant=0; 

    HBITMAP sect=CreateDIBSection(DCMem,&bmi,DIB_RGB_COLORS,&pBits,NULL,0); 
    HBITMAP tbmp=(HBITMAP)DCMem.SelectObject(sect);

    //сначала что-то рисуем "обычными срдствами"
    DCMem.FillSolidRect(0,0,rect.Width(),rect.Height(),RGB(255,255,255));
    DCMem.MoveTo(0,0);
    DCMem.LineTo(rect.Width(),rect.Height());

    //а теперь хотим работать с битами цвета напрямую
    int *uu=(int*)pBits;
    for (int y=0;y<h;y++) 
    for (int x=0;x<w;x++)
    {
        COLORREF c=*uu;
        unsigned char r,g,b;
        r=GetRValue(c);
        g=GetGValue(c);
        b=GetBValue(c);
        b=0xFF; //хотим "усилить" синий оттенок по всему изображению
        c=RGB(r,g,b);
        *uu=c;
        uu++;
    } 
    //копируем контекст
    dcDest.BitBlt(0,0,rect.Width(),rect.Height(),&DCMem,0,0,SRCCOPY);
    DCMem.SelectObject(tbmp);
}


Вот в случае с 24-битном цветом код получается компактнее, но прядок байт все равно получается перепутанным..Вот код:
Код

void CDIBDlg::OnPaint() 
{
    CRect rect;
    GetClientRect(&rect);
    CPaintDC dcDest(this); // device context for painting

    CDC DCMem;
    DCMem.CreateCompatibleDC(&dcDest);
    VOID *pBits; 
    int w=rect.Width();
    int h=rect.Height(); 
    BITMAPINFO bmi; 
    bmi.bmiHeader.biSize= sizeof(BITMAPINFOHEADER); 
    bmi.bmiHeader.biWidth=w; 
    bmi.bmiHeader.biHeight= h; 
    bmi.bmiHeader.biPlanes=1; 
    bmi.bmiHeader.biBitCount=24; 
    bmi.bmiHeader.biCompression=BI_RGB; 
    bmi.bmiHeader.biSizeImage=0; 
    bmi.bmiHeader.biClrUsed=0; 
    bmi.bmiHeader.biClrImportant=0; 

    HBITMAP sect=CreateDIBSection(DCMem,&bmi,DIB_RGB_COLORS,&pBits,NULL,0); 
    HBITMAP tbmp=(HBITMAP)DCMem.SelectObject(sect);

    //сначала что-то рисуем "обычными срдствами"
    DCMem.FillSolidRect(0,0,rect.Width(),rect.Height(),RGB(255,255,255));
    DCMem.MoveTo(0,0);
    DCMem.LineTo(rect.Width(),rect.Height());

    //а теперь хотим работать с битами цвета напрямую
    int *uu=(int*)pBits;
    unsigned char *cu=(unsigned char*)pBits;
    for (int y=0;y<h;y++) 
    for (int x=0;x<w;x++)
    {
        unsigned char *r,*g,*b;
        r=cu;
        g=cu+1;
        b=cu+2;
        *b=0xFF; //хотим "усилить" синий оттенок по всему изображению
        cu+=3;
    } 
    //копируем контекст
    dcDest.BitBlt(0,0,rect.Width(),rect.Height(),&DCMem,0,0,SRCCOPY);
    DCMem.SelectObject(tbmp);
}



Кстати, зависит ли работоспособность такого кода от настроек винды? (допустим, будет ли разница, еслли будет выбран TRUECOLOR или HICOLOR)? 
(сам проверить не могу, драйвера не позволяют 24битный цвет в винде выставить, только 32).


Это сообщение отредактировал(а) Dreamer_0x01 - 17.8.2007, 13:28


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
zkv
Дата 17.8.2007, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Участник Клуба
Сообщений: 2133
Регистрация: 23.7.2006
Где: Санкт-Петербург

Репутация: 16
Всего: 92



Цитата(Dreamer_0x01 @  17.8.2007,  13:27 Найти цитируемый пост)
AARRGGBB,

в 24-битной порядок BGR (уверен)
в 32-битной порядок BGRA (не уверен на 100%)
PM MAIL   Вверх
Dreamer_0x01
Дата 17.8.2007, 15:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



Цитата

порядок BGRA


B,G,R - понятно. А что такое А ?


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Earnest
Дата 17.8.2007, 15:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



1) ДИБ-секцию надо прибивать, сама не умрет. Просто вызвать DeleteObject (hBitmap). Биты вроде освобождать самому не надо - не ты же их выделяешь...

2) Код доступа к цветам лучше выделить в отдельные функции - для каждого цвета написать свои варианты GetPixel и SetPixel, и устанавливать указатели на эти функции при инициализации.
Написать что-то вроде универсального класса CDibSection, куда все это засунуть.

3) Я предпочитаю работать не с COLORREF-цветом, а написала себе маленький классик CRgb, где байты цвета идут в том порядке, как они встречаются в растре + функции преобразования:

Код

#pragma pack (push)
#pragma pack (1)

struct CRgb
{
   BYTE m_b, m_g, m_r;

   CRgb (): m_b(0), m_g(0), m_r(0) {}
   CRgb (BYTE r, BYTE g, BYTE b): m_b(b), m_g(g), m_r(r) {}
   CRgb (COLORREF clr): m_b(GetBValue(clr)), m_g(GetGValue(clr)), m_r(GetRValue(clr)) {}
   CRgb (RGBQUAD q): m_b(q.rgbBlue), m_g(q.rgbGreen), m_r(q.rgbRed) {}

   bool operator == (const CRgb& clr) const { return m_r == clr.m_r && m_g == clr.m_g && m_b == clr.m_b; }
   bool operator != (const CRgb& clr) const { return !operator == (clr); }
    bool operator <  (const CRgb& clr) const { return Value() < clr.Value(); }

   // это не COLORREF, а то, что лежит в дибе !!!
   PIXEL        Value() const { return (m_b) | ((UINT)m_g << 8) | ((UINT)m_r << 16); }
    COLORREF Color() const { return RGB (m_r, m_g, m_b);    }
    RGBQUAD  RgbQuad() const 
    {
        RGBQUAD q = { m_b, m_g, m_r, 0 };
        return q;
    }
};

#pragma pack (pop)



--------------------
...
PM   Вверх
zkv
Дата 17.8.2007, 15:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Участник Клуба
Сообщений: 2133
Регистрация: 23.7.2006
Где: Санкт-Петербург

Репутация: 16
Всего: 92



Цитата(Dreamer_0x01 @  17.8.2007,  15:35 Найти цитируемый пост)
B,G,R - понятно. А что такое А

alpha-канал, характеризует прозрачность пикселя, где и как используется не знаю, знаю что на него можно просто забить smile
PM MAIL   Вверх
Dreamer_0x01
Дата 20.8.2007, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


Профиль
Группа: Участник
Сообщений: 780
Регистрация: 14.4.2005
Где: Санкт-Петербург

Репутация: 9
Всего: 12



Earnest, 
у меня снова проблема. Я хочу создать класс, который умеет себя отрисовывать (допустим, в функции Draw())в контексте, указатель на который передается в функцию рисования.

Делать это хочу вышеуказанным способом. Проблема вот в чем. Если я внутри функции создаю DIB-секцию, потом привязываю к переданному контексту, потом редактирую биты, а потом делаю SelectObject предыдущего битмапа, и убиваю DIB-секцию, то попросту ничего не рисуется. Приходится для этого создавать еще один контекст в памяти, DIB-секцию создавать именно для него, потом делать BitBlt на передаваемый контекст, и уже после этого убивать DIB-секцию. В итоге имеем лишнее копирование растра, и как следствие, если рисуем несколько объектов, то сильно затормаживаем процесс перерисовки.

Как бы сделать так, чтобы внутри функции DIB-секцию можно было создать именно для передаваемого контекста, и там же ее прибить? 


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Earnest
Дата 20.8.2007, 14:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Совсем ничего не поняла. По-моему, ты что-то перемудрил...
Во-первых, зачем тебе создавать DIB-секцию каждый раз заново? Создай один раз и пользуй сколько хочешь: в функции OnDraw нужно всего лишь прицепить секцию к CompatibleDC... Да и последний я бы не стала каждый раз создавать-удалять... зачем?
Конечно, если ты прицепишь только что созданный битмап к контексту, он будет пуст...
Короче, все может выглядеть приблизительно так: диб секция и мемори-контекст создаются один раз (для экземпляра класса, видимо), в эту диб-секцию ты рисуешь и курочишь биты когда хошь (тем, кстати, мемори-контексты хороши - ковыряйся в любой момент), а в функции OnDraw всего лишь копируешь биты (BitBlt) из мемори контекста в переданный экранный... ты ведь видишь именно экран, а мемори-контексты - они невидимые...

Какое-то у меня смутное подозрение, что ты пытаешься прицепить диб-секцию к экранному контексту... бесполезное это занятие... На диб секции ты можешь рисовать только из мемори-контекста, а в экранный  - копировать функцией BitBlt - кстати очень быстрая функция. 


--------------------
...
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.0530 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.