November 11, 2005

Баг в ASUS A620(BT) с SHLoadImage

Вот собственно всплыл следующий баг девайса недавно у меня.
API-функция

HBITMAP ::SHLoadImage(LPCTSTR lpszImageName);

грузит .gif файлы по доккументации (реально она почти все графические форматы грузит, даже png, причем начиная с PocketPC 2002 :), и возвращает HBITMAP с созданной картинкой. Дык вот, цвета в этой картинке грузятся в формате 555 (т.е. 2 байта на пиксель, по 5 бит на каждый канал из RGB). При выводе на любой Compatible DC нормального девайса цвет автоматически преобразуется в 565 формат (экран-то у нас все-таки 16бит...) и выводится на экран. Дык нет же. Эти **** (ASUS это ведь Тайвань, да? Или Корея? Я уже и запутался...) умудрились переконвертить зеленый цвет из 5ти бит в 6ти-битное значение просто сдвигом влево...

WORD nGreen6 = nGreen5 << 1;

Сообразили? И все картинки загруженые этой фцией благополучно отображаются с фиолетовым оттенком. Потому-что последний бит зеленого всегда = 0... Это конечно не очень заметно на "цветастых" цветах. Но вот когда на такой картинке с белым фоном отображается белый системный контрол...
Ужоснах.

PS. Кстати, это можно исправить :) Только влом :)) Идея в том, что мы грузим таким образом картинку, берем ее биты из BITMAP.bmBits (да, именно так). И нормально конвертим в 565 цвет, создавая нормальный compatible bitmap с 16 битами на пиксель (ибо девайс такие битмапы уже по дефолту будет считать как 565 цветовой формат). Могу предположить даже, что лучше всего на ARM так сделать конвертирование цвета из 555 в 565:

; Предположим, что r0 содержит цвет в RGB 555, а регистры r1 и r2 сохранены
; гденить типа стека (или вообще не использовались :)
ands      r1, r0, #0x3E0       ; Теперь в r1 зеленый, но не сдвинутый.
cmp       r1, #0
orrne     r1, r1, #0x10        ; Выставим последний бит в 1 если зеленый
                               ; канал вообще присутствует в цвете :)
and       r2, r0, #0x1F        ; Чистый красный в r2
orr       r2, r2, r1, lsl 1    ; 6ти-битный зеленый сдвинутый на 1 влево
                               ; сORенный с красным.
mov       r1, r0, lsr 10       ; В больше не нужном r1 - чистый синий
orr       r0, r2, r1, lsl 11   ; Синий сдвинутый для 565 сORиваем с остальными
; Вот теперь r0 содержит RGB 565 :)