WinGDI. Преобразование цвета 32 <-> 8. Непонятки с палитрой.

Тема в разделе "WASM.BEGINNERS", создана пользователем Span, 23 янв 2007.

  1. Span

    Span New Member

    Публикаций:
    0
    Регистрация:
    5 ноя 2006
    Сообщения:
    134
    Всем доброго времени суток!

    Никогда не работал до этого с WinGDI.

    Задача - рисовать рисунки и сохранять в BMP файлы. Компрессия RLE, формат - 8 бит на байт.
    рисунки в дальнейшем передаются по сети, поэтому размер критичен. Никаких 4х байт на точку нельзя допустить. рисунки не сложные, в основном из закрашенных прямоугольных областей, поэтому RLE дает хороший результат сжатия.

    Как делаю:
    Сначала
    hDC = CreateCompatibleDC()
    hBMP = CreateCompatibleBitmap(hDC, w, h)
    SelectObject(hDC, hBMP)

    потом рисую что надо

    Далее описываю BITMAPINFOHEADER:

    bih.biSize=sizeof(BITMAPINFOHEADER);
    bih.biWidth=w;
    bih.biHeight=h;
    bih.biPlanes=1;
    bih.biBitCount=8;
    bih.biCompression=BI_RLE8;
    bih.biSizeImage=0;
    bih.biXPelsPerMeter=0;
    bih.biYPelsPerMeter=0;
    bih.biClrUsed=0;
    bih.biClrImportant=0;

    В нем явно указываю, что хочу по 8 бит на точку.

    Затем получаю BITMAPINFO : GetDIBits(hDC, hBmp, 0, 0, NULL, &bi, DIB_RGB_COLORS);
    Теперь предполагаю, что в bi.bmiColors лежит палитра, размером 256, тип RGBQUAD
    Потом считываю нужные биты картинки : GetDIBits(hDC, hBmp, 0, bi.bmiHeader.biHeight, bmpData, &bi, DIB_RGB_COLORS);

    Заполняю BITMAPFILEHEADER.
    И пишу всё в файл:
    >>BITMAPFILEHEADER>>bi.bmiHeader>>bi.bmiColors>>bmpData

    Файл получается нормального формата, читается чем угодно.
    Но!!! на месте палитры, лежат какие-то непонятные данные, не похоже на цвета.
    И что бы я не рисовал, рисуется цветом 255! (если выключить компрессию, то видно, весь рисунок состоит из 0x00 и 0xFF). А в таблице на этих местах просто непонятные данные! отсюда рисунок состоит совсем не из тех цветов, которые я хотел использовать...

    Куда копать??
    Как вообще можно преобразовать формат 32 бита на точку в 8 бит на точку? понятно, что потери будут. Но как искать подхлдящие цвета?
    Вообще на рисунки всего не больше 10ти разных цветов используется.

    Ниже привел код всего этого безобразия:
    Код (Text):
    1.     int h=100;
    2.     int w=200;
    3.     BITMAPFILEHEADER hdr;
    4.     BITMAPINFOHEADER bih;     // bitmap info-header
    5.     BITMAPINFO  bi;
    6.  
    7.     //BITMAPINFOHEADER
    8.     bih.biSize=sizeof(BITMAPINFOHEADER);
    9.     bih.biWidth=w;
    10.     bih.biHeight=h;
    11.     bih.biPlanes=1;
    12.     bih.biBitCount=8;
    13.     //bih.biCompression=BI_RLE8;
    14.     bih.biCompression=0;
    15.     bih.biSizeImage=0;
    16.     bih.biXPelsPerMeter=0;
    17.     bih.biYPelsPerMeter=0;
    18.     bih.biClrUsed=0;
    19.     bih.biClrImportant=0;
    20.  
    21.     //BITMAPINFO
    22.     bi.bmiHeader=bih;
    23.    
    24.     //Create  Dc    
    25.     HDC hDC = CreateCompatibleDC(NULL);
    26.     HBITMAP hBmp = CreateCompatibleBitmap(hDC, w, h);
    27.    
    28.  
    29.     //BMP
    30.     SelectObject(hDC, hBmp);
    31.  
    32.  
    33.     //BRUSH
    34.     hBRUSH = CreateSolidBrush(RGB(0x00,0x70,0x70));
    35.     SelectObject(hDC, hBRUSH);
    36.  
    37.     //Rectangle
    38.     Rectangle(hDC, 40,40,80,80);
    39.  
    40.     //Text
    41.     TextOut(hDC, 20, 20, "test",4);
    42.     GetDIBits(hDC, hBmp, 0, 0, NULL, &bi, DIB_RGB_COLORS);
    43.  
    44.     BYTE * bmpData=(BYTE *)malloc(bi.bmiHeader.biSizeImage);
    45.  
    46.     GetDIBits(hDC, hBmp, 0, bi.bmiHeader.biHeight, bmpData, &bi, DIB_RGB_COLORS);
    47.  
    48.     HANDLE hf = CreateFile("c:\\img.bmp", GENERIC_READ | GENERIC_WRITE, (DWORD) 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);
    49.     DWORD dwTmp;
    50.  
    51.     //BITMAPFILEHEADER
    52.     hdr.bfSize=sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*(1 << bi.bmiHeader.biBitCount) + bi.bmiHeader.biSizeImage;
    53.     hdr.bfType=0x4D42;
    54.     hdr.bfReserved1=0;
    55.     hdr.bfReserved2=0;
    56.     hdr.bfOffBits=sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*(1 << bi.bmiHeader.biBitCount);
    57.  
    58.     WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL);
    59.     WriteFile(hf, (LPVOID) &bi.bmiHeader, sizeof(BITMAPINFOHEADER), (LPDWORD) &dwTmp, NULL);
    60.     WriteFile(hf, (LPVOID) bi.bmiColors, sizeof(RGBQUAD) * (1 << bi.bmiHeader.biBitCount),   (LPDWORD) &dwTmp, NULL);
    61.    
    62.     WriteFile(hf, (LPSTR) bmpData, bi.bmiHeader.biSizeImage, (LPDWORD) &dwTmp,NULL);
    63.  
    64.     // Close the .BMP file.
    65.      CloseHandle(hf);
     
  2. Span

    Span New Member

    Публикаций:
    0
    Регистрация:
    5 ноя 2006
    Сообщения:
    134
    Может в другую ветку кинуть?

    Или форум другой. Кстати, кто знает форумы похожего содержания за бугром???
     
  3. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    Span
    я не думаю, что на этом форуме много UI-программистов
     
  4. CodeTao

    CodeTao Евгений

    Публикаций:
    0
    Регистрация:
    31 окт 2006
    Сообщения:
    177
    Адрес:
    штаты
    Советую посмотреть как это реализует сам майкросовт - в примерах SDK есть ViewDIB, она как раз такое и делает.
     
  5. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    Вот этот код я считаю неверным. Коварная ошибка скрыта в нем.
    Код (Text):
    1. HDC hDC = CreateCompatibleDC(NULL);
    2. HBITMAP hBmp = CreateCompatibleBitmap(hDC, w, h);
    Попробуй след:
    Код (Text):
    1. HDC sDC = GetDC (0);
    2. HDC hDC = CreateCompatibleDC(sDC);
    3. HBITMAP hBmp = CreateCompatibleBitmap(sDC, w, h);
    4. ReleaseDC (0, sDC);
    Фишка, в том что у контекста устройства, пока ты его не привязал к определенному растру, уже есть стандартный растр, который (из экономии?) собой представляет монохромную картинку размером 1х1 пиксель. Используя этот контекст, в качестве образца для создания растра требуемых размеров, ты фактически заказываешь себе монохромный растр.
     
  6. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Span
    Как вообще можно преобразовать формат 32 бита на точку в 8 бит на точку?
    Цитат из Feng Yuan. Windows Graphics Programming Win32 GDI and DirectDraw (R). 13.6 BITMAP COLOR-DEPTH REDUCTION: "Now that we have a good algorithm to find the “optimal” palette of a bitmap, the next fun thing to try is reducing high-color or bitmap-color bitmaps to index-based bitmaps, or generally to reduce the color depth of a bitmap. For example, we can convert a true color image to an 8-bpp image, reducing it to one-third of its original size plus any gain from RLE compression. We can also convert an 8-bpp to a 4-bpp image."

    Файл получается нормального формата.
    Я не встречался с RLE-сжатыми картинками. Можешь прицепить сюда?
     
  7. Span

    Span New Member

    Публикаций:
    0
    Регистрация:
    5 ноя 2006
    Сообщения:
    134
    alpet - Спасибо!!!!

    Прицепить сам битмап?
     
  8. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Span
    Прицепи битмап, который "получается нормального формата". Он действительно сжат RLE8?
     
  9. Span

    Span New Member

    Публикаций:
    0
    Регистрация:
    5 ноя 2006
    Сообщения:
    134
    Прилепил, там картинка 200 на 100. Глубина цвета - 8 бит. Компрессия RLE8.
     
  10. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Если не секрет, это должно быть в БМПшнике?
    Код (Text):
    1. C:\WINDOWS\WinSxs\
    2. Microsoft.Windows.SystemCompatible,processorArchitecture="x86",publicKeyToken="6595b64144ccf1df",type="win32",version="5b?
     
  11. RamMerLabs

    RamMerLabs Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 сен 2006
    Сообщения:
    1.426
    Посмотри как это сделано в XnView, я кажется где-то видел к нему плагин с открытыми исходниками.