01:29

Тотальная неудачница и убийца жёстких дисков.
#post-id: 2435-00-20

#original-date: 27.03.2007 Tue

#original-time: 12:20 AM

#original-day:  2435



Так, Aulith спрашивал, как я выкрутилась с растрами. Собственно вот так:



//===================================================================

// Функция принимает манипулятор растра и создаёт её копию в
// двадцатичетырёхбитном цвете. Это полезно, когда требуются
// манипуляторы с копией изображения загруженного из, например, GIF
// или выбранного уже где-то.
//===================================================================
EXP_AJPAPI(HRESULT) asCopyBitmap(HBITMAP hSourceBitmap,
                                HBITMAP *RetVal)
{
 CHECK_RETVAL;
 
 // Проверяем тип объекта
 if (GetObjectType((HGDIOBJ)hSourceBitmap) != OBJ_BITMAP)
   return E_INVALIDARG;
 
 //=================================================================
 // Тут мы создаём копию растра - дело в том, что если наш растр уже
 // выбран где-то, то повторно его выбрать не удастся. Так что
 // копируем его через CopyImage().
 //
 // Внимание! Флаг LR_CREATEDIBSECTION в этой функции не был описан
 // в документации. Я его использовала на свой страх и риск, и оно
 // сработало! Дело в том, что при использовании 256 цветного
 // рисунка, коггда мы создаём копию, при BitBlt() цвета могут
 // съехать. Не помогает даже DIB секция в качестве приёмника! Но
 // если скопировать изображение в DIB секцию этой функцией, то
 // можно всё это решить. Не знаю, будет ли оно работать на NT...
 HBITMAP hBitmap = (HBITMAP)CopyImage(hSourceBitmap, IMAGE_BITMAP,
                                      0, 0, LR_COPYRETURNORG |
                                      LR_CREATEDIBSECTION);
 if (!hBitmap) return S_FALSE;
 
 //=================================================================
 // Создаём контекст устройства источника, где выберим тот
 // скопированный растр. Также и приёмник сделаем...
 HDC hCompDC = CreateCompatibleDC(0);
 if (!hCompDC) {
   DeleteObject(hBitmap);
   return S_FALSE;
 }
 
 HDC hNewDC = CreateCompatibleDC(0);
 if (!hNewDC) {
   DeleteDC(hCompDC);
   DeleteObject(hBitmap);
   return S_FALSE;
 }
 
 //=================================================================
 HBITMAP hOldCompBitmap = (HBITMAP)SelectObject(hCompDC, hBitmap);
 if (!hOldCompBitmap) {
   DeleteDC(hCompDC);
   DeleteDC(hNewDC);
   DeleteObject(hBitmap);
   return S_FALSE;
 }
 
 BITMAP BM;
 GetObject(hBitmap, sizeof(BM), &BM);
 
 // Создаём растр-приёмник как DIB секцию, чтобы избежать проблем с
 // цветами. Первые два варианта - на память. CreateBitmap()
 // работает, но что-то не очень хочется на него полагаться, както
 // он меня подвёл. А вот CreateCompatibleBitmap() создаёт в случае
 // с 256 цветным рисунком точно такойже, чего нам не надо.
 //
 // mvarhBitmap = CreateBitmap(BM.bmWidth, BM.bmHeight, 1, 24, ByVal 0&)
 // mvarhBitmap = CreateCompatibleBitmap(hCompDC, BM.bmWidth, BM.bmHeight)
 
 BITMAPINFO BMI;
 ZeroMemory(&BMI, sizeof(BMI));
 
 BMI.bmiHeader.biSize = 40;
 BMI.bmiHeader.biWidth = BM.bmWidth;
 BMI.bmiHeader.biHeight = -BM.bmHeight;
 BMI.bmiHeader.biPlanes = 1;
 BMI.bmiHeader.biBitCount = 24; // то что надо!
 BMI.bmiHeader.biCompression = BI_RGB;
 
 HBITMAP hNewBitmap = CreateDIBSection(0, &BMI, DIB_RGB_COLORS, NULL, 0, 0);
 if (!hNewBitmap) {
   SelectObject(hCompDC, hOldCompBitmap);
   DeleteObject(hBitmap);
   
   DeleteDC(hCompDC);
   DeleteDC(hNewDC);
   
   return S_FALSE;
 }
 
 // Выбираем и копируем!
 HBITMAP hOldBitmap = (HBITMAP)SelectObject(hNewDC, hNewBitmap);
 BitBlt(hNewDC, 0, 0, BM.bmWidth, BM.bmHeight, hCompDC, 0, 0, SRCCOPY);
 
 //=================================================================
 // А теперь отчищаем ресурсы.
 SelectObject(hCompDC, hOldCompBitmap);
 SelectObject(hNewDC, hOldBitmap);
 
 DeleteDC(hCompDC);
 DeleteDC(hNewDC);
 
 DeleteObject(hBitmap);
 *RetVal = hNewBitmap;
 
 return S_OK;
}
Это код на VC++. EXP_AJPAPI(HRESULT) означает HRESULT __stdcall, просто в виде макроса. Мне так нравится. Вот... Собственно, код делает DIB секцию вместо растра и в итоге далает растр независимым от палитр и прочего. Как я сказала в комментах, это избавляет от многих проблем при манипуляциях с растрами в памяти. А ведь на этом и спотыкался поначалу Wallpaper Changer. С JPG ресамплинг шёл нормально, а с GIF - нет. До этого я ресамплинг не делала - только делала растр по масштабу экрана, а Windows уже делала сама ресамплинг. Вот. Но когда взялась за всё сама, нашла проблему с растрами с палитрой. А потом ещё были проблемы с порчей видеопамяти на S3 ViRGE MX. За эту функцию (которую я писала три дня) видюшка до сих пор говорит мне спасибо ^_^



Кстати, код работает (как оказалось) и в 9x и в NT. Так что, можно смело юзать ^_^



Кстати, может показаться, что достаточно только CopyImage() с флагом LR_CREATEDIBSECTION, у меня у самой регулярно возникает такое подозрение, но когда я начинаю разбираться снова и снова, через часик-другой вспоминаю, какие были причины... Так что, считайте, что так нужно ^_^'

Комментарии
29.03.2007 в 23:06

 
а все-таки, результат этих манипуляций каков? просто явное создание DIB секции?

и в каком месте это копирование предполагается выполнять, при загрузке bitmap'ов, дабы далее полученные копии непосредственно прорисовывать?

странно, как это может повлиять на прозрачность, если в @клиенте это - изначально 24битные BITMAP...
30.03.2007 в 09:40

Тотальная неудачница и убийца жёстких дисков.
Эммм... Неет ^_^' Это не к прозрачности, а к тому нашему разговору про то как я воевала с S3 ViRGE MX ^^ Просто, для примера код. Рассчитан на VB, где работа с растрами тоже полна неожиданностей и сюрпризов. А вот где его можно применить в клиенте... Ну... Не знаю ^^



В Wallaper Changer я использовала так:

-- Гружу картинку через LoadPicture() для JPG, BMP и GIF или через одну библиотеку для форматов вроде PSD.

-- Копирую растр этой функцией из Pic.Handle, чтобы не зависеть от растра в объекте в StdPicture.

-- Делаю ресамплинг.

-- Копирую на пропорциональный экрану растр.

-- Новый растр загоняю в StdPicture.

-- Сохраняю картинку в BMP через SavePicture().

-- Ну и ставлю на рабочий стол ^^
31.03.2007 в 17:03

 
а... это разве не один и тот же разговор был? ^_^

в принципе в клиенте ресемплинг делается только в пределах своего формата (gif, png, jpg) и жалоб на него вроде не было... по крайней мере в последнее время)



а кстати в Delphi у TBitmap есть метод для явного создания DIB секции... только там вроде никакого копирования не используется...



мне вот действительно надо разобраться с тем глюком прозрачности и гифами анимированными, ага. я подумал, что это к тому)