Форум: "WinAPI";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.02.04;
Скачать: [xml.tar.bz2];




Вниз

Вывод bitmap из ресурса 


sandman   (2001-11-20 14:42) [0]

Имеется проблема: в файле есть несколько ресурсов типа BITMAP (256 цветов). При просмотре этих картинок в Фотошопе цвета выглядят нормально, но при загрузке их в Delphi Image Editor, а также непосредственно в программу палитра "плывёт". Есть ли какой-нибудь способ побороть это?



-=CrazyFish=-   (2001-11-20 17:37) [1]

Нужно воспользоваться утилитой brcc32.exe из папки bin.
нужно создать файл RC (myResFile.rc)
прописать в нем, например:

myBitmapName1 BITMAP bitmapFile1.bmp
myBitmapName2 BITMAP bitmapFile2.bmp
myBitmapName3 BITMAP bitmapFile3.bmp

и выполнить brcc32.exe myResFile.rc

получишь myResFile.res, в котором все битмэпки будут иметь нужную палитру

Так же можно пользоваться редактором ресурсов из Visual Studio, там есть возможность подгружать нужную палитру.
Удачи.



_mike   (2001-11-20 17:46) [2]

to CrazyFish

Всё это замечательно, но только палитра всё равно плывет. Лично у меня выводится всего 2-3 цвета (цвета монохромные, но картинка использует около 200 цветов).



-=CrazyFish=-   (2001-11-20 18:03) [3]

> _mike
ну... если на экран одновременно выводится несколько картинок с разными палитрами, а видеорежим на 256 цветов, то все легко можел поплыть.
Если кол-во цветов больше 256, то ничего сказать не могу, у меня таких проблем не возникало.



_mike   (2001-11-21 19:52) [4]

-=CrazyFish=-, посмотри своим опытным глазом, может я туфту тут написал? Ну не могут всего два цвета выводиться. Ну 20-30, но не два.
Посмотри, -=CrazyFish=-, будь другом. Пожалуйста.


var BitMap_MainBox: HBitMap;
var TheDC, hdc_Main_Box: HDC;
var Handle: HWND;

procedure LoadMyResourses;
begin
BitMap_MainBox:=LoadBitmap(hInstance,"MAINBOX");
TheDC:=GetDC(Handle);
hdc_Main_Box := CreateCompatibleDC(TheDC);
SelectObject(hdc_Main_Box, BitMap_MainBox);
ReleaseDC(Handle,TheDC);
end;

procedure DrawElement(X, Y, Width, Height: integer;
ID_Paint_Element:HDC; deltaX, DeltaY: integer; Operation: integer);
var PS: TPaintStruct;
begin
TheDC:=BeginPaint(Handle,PS);
BitBlt(TheDC,X,Y,Width,Height,ID_Paint_Element,deltaX,deltaY,Operation);
EndPaint(Handle,PS);
end;

procedure DrawMainBox;
begin
DrawElement(0,0,276,350,hdc_Main_Box,0,0,SrcCopy);
end;





Evgeny   (2001-11-22 14:42) [5]

Если я правильно понял, то процедура DrawElement выполняется из WM_PAINT.
Тогда этот кусок можно выполнить так:

BeginPaint(Handle,PS);
BitBlt(PS.DC,X,Y,Width,Height,ID_Paint_Element,deltaX,deltaY,Operation);
EndPaint(Handle,PS);



_mike   (2001-11-22 15:00) [6]

Evgeny.
Ну да.

Спасибо, я попробую. Хотя я думаю, что ошибка не в этом. В любом случае завтра напишу что у меня получилось (Все ресурсы на домашнем компе, а сейчас я на работе).

В любом случае, спасибо за отклик.



_mike   (2001-11-23 12:24) [7]

Evgeny, пробывал я вчера. Та же история. Я понял вчера только одно: битмэп она воспринимает с политрой в 16 цветов, почему то. У меня мысля возникла, может это из-за того, что стиль окна у меня только WS_POPUP?



Evgeny   (2001-11-23 14:48) [8]

Стиль здесь не причем. Не совсем понятно как у тебя взаимосвязаны процедуры. У меня вывод делается примерно таким же способом, и все идет нормально. Все битмапы я, для экономии места, всегда оптимизирую на 256 цветов и проблем пока не было. А разрешение экрана у тебя случайно не 256 цветов? При этом Windows любую картинку у которой палитра не совпадает с системной выведет в 16 цветов. Да. И укажи куда выводишь. Мне кажется непосредственно на окно.



_mike   (2001-11-23 15:33) [9]

Evgeny.
Суть заключается в следующем. Я хочу чтобы моя програмка работала на абсолютно любом компе и в любом режиме. Естественно, что при палитровом разрешении экрана, например в 16 и больше бит, всё выводится нормально. Тут проблем нет. Но стоит мне режим переключить в 256 цветов - программка воспринимает ресурс как 16-ти цветовой.

Не знаешь как преодолеть эту проблему?



_mike   (2001-11-23 15:43) [10]

Evgeny, забыл написать про взаимодействие процедур :)
Из основномо модуля процедура LoadMyResourses вызывается по событию WM_Create, a DrawMainBox - по событию WM_Paint. Вывожу сразу в окно.

Спасибо за участие.



Evgeny   (2001-11-26 09:59) [11]

Ну тогда все понятно. Нормальное изображение в данном случае можно получить только в случае приведения палитры в твоих файлах к системной. Во всех остальных случаях система будет скидывать цвета до 16. Обрати внимание на различные инсталляторы. Их бедные цветами картинки именно из-за желания видеть изображение одинаковым во всех цветовых разрешениях.



_mike   (2001-11-26 13:03) [12]

Evgeny
Да, но если использовать вместо WIN32 API, например, TImage (IDE), то эта проблема как то решается... Может всё таки можно как то её решить средствами WIN32 API?



Evgeny   (2001-11-26 15:03) [13]

Прочитал и усомнился. Решил проверить. Проверил. Понял, что _mike сам этого никогда не проверял. Начинаем проект, кладем на него TImage, выбираем 256-цветный битмап, палитра которого далека от системной. Все красиво. Переключаем экран в режим 256 цветов. Тихо офигеваем. И не мудрено - цвета кошмарные. Переключаюсь обратно в 16 бит. Все нормально и красиво. Так что _mike извини. Оптимизируй под системную палитру.



_mike   (2001-11-26 18:18) [14]

Переключаюсь в режим 256-цветов.
Открываю стандартный редактор картинок Paint.
Загружаю картинку - цвета подобраны удовлитворительно.
То же самое с другими редактарами и просмоторщиками.
При этом палитра картинки не оптимизирована под системную...



ggsoft   (2001-11-26 22:37) [15]

to _Mike, Delphi-йский ImageEditor тоже конкретно глючит при открытии Image-й на 256-цветах и последующего их сохранения, попробуй! VC6 не глючит.

Evgeny, не все вышесказанное правильно. При выводе изображений на 256-цветах, Windows не «скидывает» их (цвета изображения) до 16 цветов, а пытается подобрать палитру изображения к своей системной. И это происходит во время загрузки рисунка в HBITMAP т. е. из DIB-изображения Windows преобразует DDB, а значит надо при выводе рисунка создать и выбрать в контекст устройства ( HDC) свою палитру, полученную из рисунка... Ниже код, правда я писал его на VC6.

to _Mike, если не сможете перевести на Delphi пишите.



/********************************************************************/
//Загрузить изображение и создать палитру
/********************************************************************/
BOOL CGGAboutDlgLogoBmp::GetBitmapAndPalette(CBitmap &bmpPaint, CPalette &palPaint)
{
HBITMAP hBmp;
DIBSECTION ds;
BITMAPINFOHEADER &bmpInfoHdr = ds.dsBmih;
UINT nColors;
CWindowDC dcDesktop(NULL);
CDC dcMem;
CBitmap *bmpTemp;
RGBQUAD *pRGB;
LOGPALETTE *pPal;
BOOL bRet = FALSE;

if (bmpPaint.m_hObject)
bmpPaint.DeleteObject();
if (palPaint.m_hObject)
palPaint.DeleteObject();

hBmp = (HBITMAP)::LoadImage(AfxGetResourceHandle(),
MAKEINTRESOURCE(GG_IDB_LOGOABOUT), IMAGE_BITMAP,
0, 0, LR_CREATEDIBSECTION);
if (!hBmp)
return FALSE;

bmpPaint.Attach(hBmp);
bmpPaint.GetObject(sizeof(ds), &ds);
nColors = bmpInfoHdr.biClrUsed ?
bmpInfoHdr.biClrUsed : 1 << bmpInfoHdr.biBitCount;

dcMem.CreateCompatibleDC(&dcDesktop);
bmpTemp = dcMem.SelectObject(&bmpPaint);
pRGB = new RGBQUAD [nColors];
pPal = (LOGPALETTE *)new BYTE [sizeof(LOGPALETTE) +
sizeof(PALETTEENTRY) * nColors];
pPal->palNumEntries = nColors;
pPal->palVersion = PALETTEVERSION;
if (GetDIBColorTable(dcMem, 0, nColors, pRGB) == nColors) {
for (UINT i = 0; i < nColors; i++) {
pPal->palPalEntry[i].peRed = pRGB[i].rgbRed;
pPal->palPalEntry[i].peGreen = pRGB[i].rgbGreen;
pPal->palPalEntry[i].peBlue = pRGB[i].rgbBlue;
pPal->palPalEntry[i].peFlags = 0;
}
bRet = palPaint.CreatePalette(pPal);
}
else
ASSERT(FALSE); //GetDIBColorTable worked not correct

delete [] pPal;
delete [] pRGB;
dcMem.SelectObject(bmpTemp);

return bRet;
}

/********************************************************************/
//то же самое событие OnPaint Delphi-йской формы
/********************************************************************/
void CGGAboutDlgLogoBmp::OnPaint()
{
CPaintDC dc(this);
CDC dcMem;
CRect rectClient;
CBitmap *bmpTemp;
CPalette *palTemp = NULL;
BITMAP bmpInfo;

GetClientRect(&rectClient);
if (!m_pPalette)
m_pPalette = new CPalette;

if (GetBitmapAndPalette(m_bmpLogoBitmap, *m_pPalette)) {
m_bmpLogoBitmap.GetBitmap(&bmpInfo);
dcMem.CreateCompatibleDC(&dc);
bmpTemp = dcMem.SelectObject(&m_bmpLogoBitmap);
dc.SetStretchBltMode(COLORONCOLOR);
if (dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pPalette->m_hObject) {
palTemp = dc.SelectPalette(m_pPalette, FALSE);
dc.RealizePalette();
}
dc.StretchBlt(rectClient.left, rectClient.top,
rectClient.Width() - 1, rectClient.Height() - 1,
&dcMem, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight,
SRCCOPY);
if (palTemp)
dc.SelectObject(palTemp);
dcMem.SelectObject(bmpTemp);
}
}


С уважением, Евгений!



Evgeny   (2001-11-27 07:37) [16]

Существует такой же вариант и на Delphi, попробуй может подойдет. Код не мой и я его не проверял, так что за работоспособность не ручаюсь.

procedure XLoadBitmap(Instance: THandle; BitmapName: PChar;
var HB: HBitmap; var HP: HPalette);
var
DC: HDC;
BI: PBitMapInfo;
Pal: PLogPalette;
I: Integer;
ResIdHandle: THandle;
ResDataHandle: THandle;
Bitmap: HBitmap;
C: HWnd;
OldPalette, Palette: HPalette;

begin
Bitmap:= 0; Palette:=0;
HB:=0; HP:=0;
{Получить ресурс из модуля}
ResIDHandle := FindResource(Instance, BitmapName, rt_BitMap);
if ResIDHandle<>0 then begin
ResDataHandle := LoadResource(Instance, ResIDHandle);
if ResDataHandle<>0 then begin
BI:= LockResource(ResDataHandle);
if BI <> nil then begin
{256-цветный битмап?}
if BI^.bmiHeader.biBitCount = 8 then begin
{Создать палитру}
GetMem(Pal, SizeOf(TLogPalette) + 256 * SizeOf(TPaletteEntry));
for I:= 0 to 255 do
with Pal^.palPalEntry[I] do begin
peRed := BI^.bmiColors[I].rgbRed;
peGreen:= BI^.bmiColors[I].rgbGreen;
peBlue := BI^.bmiColors[I].rgbBlue;
peFlags:= 0;
end;
Pal^.palNumEntries:= 256;
Pal^.palVersion := $300;
Palette:= CreatePalette(Pal^);
FreeMem(Pal, SizeOf(TLogPalette) + 256 * SizeOf(TPaletteEntry));

{Привести цвета палитры в системные}
DC:= CreateDC("Display", nil, nil, nil);
OldPalette:= SelectPalette(DC, Palette, False);
UnrealizeObject(Palette);
RealizePalette(DC);

{Создать битмап}
BitMap:= CreateDIBitmap(DC, BI^.bmiHeader, CBM_INIT,
@PByteArray(BI)^[SizeOf(TBitMapInfo) + SizeOf(TRGBQuad) * 256 - 4],
BI^, DIB_RGB_COLORS);

{Освободить ресурсы}
UnlockResource(ResDataHandle);
FreeResource(ResDataHandle);
SelectPalette(DC, OldPalette, False);
DeleteDC(DC);
end else begin
{Не 256-цветный битмап}
UnlockResource(ResDataHandle);
FreeResource(ResDataHandle);
BitMap:= LoadBitmap(Instance, BitmapName);
end;
HB := Bitmap;
HP := Palette;
end; {BI <> nil }
end; {ResDataHandle <> 0}
end; {ResIDHandle <> 0 }
end;


procedure TForm1.FormCreate(Sender: TObject);
var
HB: HBitmap;
HP: HPalette;
begin
xLoadBitmap(hInstance, "PHOTO", HB, HP);
Image1.Picture.Bitmap.Handle :=HB;
Image1.Picture.Bitmap.Palette:=HP;
end;



_mike   (2001-11-27 14:14) [17]

ggsoft, Evgeny - большое вам спасибо. У меня сырье дома лежит. Проверю сегодня вечером. Завтра напишу как сработали ваши коды.



_mike   (2001-11-28 12:43) [18]

Evgeny
Попробывал я этот код. Цвета он подбирает более или менее. Но этот код испольщует TBitMap. С помощью этого объекта можно было бы оптимизировать цвета лучше. Вообще говоря я хотел пользоваться исключительно средства Win32 API, поскольку в моей программке будет много графических элементов (что то вроде WinAMP). Наверное мне придётся использовать ещё более низкоуровневые операции (залезать в файл, считывать структуру и т.д.). Я надеялся, что Win32 API есть уже готовые функции, но, видимо, напрасно.


ggsoft
Код, приведённый вами так же использует уже готовые классы из библиотек VC6. Я не совсем силён в этих библиотеках и столкнулся с трудностями при переводе класса CBitmap. Этот класс напоминает дельфовский тип TBitMap, но только напоминает. В связи с большим количеством графики я не хотел бы использовать дополнительные классы или объекты. Win32 API, как мне кажется, самодостаточна, хотя с ее помощью писать приходиться дольше.

Evgeny, ggsoft
Не смотря на всё вышеописанное я обязательно более пристально изучу механизм реализованный в ваших кодах. Эти кода не пропадут напрасно. Вырожаю вам искреннюю признательность за отклик и участие в данной теме. Спасибо.



Evgeny   (2001-11-30 09:33) [19]

>_mike
Уважаемый, приведенный пример полностью на WinAPI. Если под TBitmap понимается Delphi-ский объект, то вы не правы. В данной процедуре (XLoadBitmap) он не применяется.



_mike   (2001-11-30 13:03) [20]

Evgeny

Виноват :)) Вы абсолютно правы.

Тем не менее этот код не совсем хорошо оптимизирует цвета. Я могу послать Вам по почте скомпелированный эгзешник. Если запустить его в режиме 256 цветов, то Вы увидете картинку, оптимизированную объектом TBitmap. Далее на форме есть кнопка с функцией XLoadBitmap. Вы сами сможите увидеть разницу.



Evgeny   (2001-11-30 14:09) [21]

Ну что же давай поэксперементируем.



Evgeny   (2001-12-04 10:42) [22]

Проверил. Да действительно мерзко. Посмотрим EXE файл внутри, что это? Картинка то 24 битная. Нет мы так не договаривались. Разговор шел о 256 цветной. Привожу твою картинку любым редактором в 256 цветную и повторяю эксперимент. Ну вот теперь она смотрится изумительно.

procedure TForm1.FormCreate(Sender: TObject);
var
HB: HBitmap;
HP: HPalette;
begin
// Оригинал напрямую - Терпимо
Image1.Picture.Bitmap.LoadFromResourceName(hInstance, "PHOTO_16");
// Оригинал через xLoadBitmap - Мерзко
xLoadBitmap(hInstance, "PHOTO_24", HB, HP);
Image2.Picture.Bitmap.Handle := HB;
Image2.Picture.Bitmap.Palette:= HP;
// 256 цветный через xLoadBitmap - Хорошо
xLoadBitmap(hInstance, "PHOTO_8", HB, HP);
Image3.Picture.Bitmap.Handle := HB;
Image3.Picture.Bitmap.Palette:= HP;
end;



_mike   (2001-12-06 12:31) [23]

Evgeny
Забегался я тут слегка, про программирование пришлось забыть, поэтому и не отвечал долго :))

Спасибо, Evgeny :)) Всё работает. :)))

P.S. Интересно, а как серьёзные программы и компоненты оптимизируют для в видеорежиме 256 цветов палитру в 24 бит?



Evgeny   (2001-12-07 07:27) [24]

Честно говоря не знаю. Я как-то искал ответ на нечто подобное, так облазил всю "помойку", но к сожалению ничего подходящего обнаружить не удалось. Если найдешь дай знать.



_mike   (2001-12-07 14:17) [25]

Хорошо, Evgeny :)




Форум: "WinAPI";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.02.04;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.79 MB
Время: 0.025 c
1-8935            СергейКнязев          2002-01-17 17:00  2002.02.04  
Повторяю, СРОЧНО!!!!!!. Загрузка из Excel


1-8843            saviola               2002-01-17 15:40  2002.02.04  
Как получить из DateTimePicker.Date целое значение без дроби


3-8784            Mielofon              2002-01-08 10:39  2002.02.04  
Трафик посчитать


3-8782            Pete                  2002-01-03 09:57  2002.02.04  
InterBase


1-8864            Ольга                 2002-01-18 12:39  2002.02.04  
ListBox-ы и Edit-ы