Название: альтернатива BITMAPINFO в QImage
Отправлено: AD от Март 04, 2009, 17:02
Есть ли возможность заменить такой код: C++ (Qt) BITMAPINFO* pBmi; /// Заполнение картинки (для Windows) void SubSahara::FillBitmapInfo() { #ifdef Q_WS_WIN memset(pBmi,0,sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256); pBmi -> bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pBmi -> bmiHeader.biWidth = spSize.x; pBmi -> bmiHeader.biHeight = spSize.y; pBmi -> bmiHeader.biPlanes = 1; pBmi -> bmiHeader.biBitCount = 8; pBmi -> bmiHeader.biCompression = BI_RGB; pBmi -> bmiHeader.biSizeImage = 0; pBmi -> bmiHeader.biClrUsed = pDisplay -> PaletteSize(); pBmi -> bmiHeader.biClrImportant = 0; for(int i = 0; i < pBmi->bmiHeader.biClrUsed; ++i) { pBmi -> bmiColors[i].rgbRed = pDisplay -> GetPaletteR(i); pBmi -> bmiColors[i].rgbGreen = pDisplay -> GetPaletteG(i); pBmi -> bmiColors[i].rgbBlue = pDisplay -> GetPaletteB(i); } #endif // Q_WS_WIN }
Если заместо BITMAPINFO* использовать QImage*? Буду благодарен за приведенный код!
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: pastor от Март 04, 2009, 17:18
см. описание QImage в ассистанте. Вот подобный пример из него: C++ (Qt) QImage image(3, 3, QImage::Format_RGB32); QRgb value; value = qRgb(189, 149, 39); // 0xffbd9527 image.setPixel(1, 1, value); value = qRgb(122, 163, 39); // 0xff7aa327 image.setPixel(0, 1, value); image.setPixel(1, 0, value); value = qRgb(237, 187, 51); // 0xffedba31 image.setPixel(2, 1, value);
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: Dendy от Март 04, 2009, 17:19
C++ (Qt) const QSize size( spSize.x, spSize.y ); QImage image( size, QImage::Format_ARGB32 ); int i = 0; for ( int y = 0; y < size.height(); ++y ) { uchar * p = image.scanLine( y ); for ( int x = 0; x < size.width(); ++x ) { p[0] = 255; p[1] = pDisplay->GetPaletteR( i ); p[2] = pDisplay->GetPaletteG( i ); p[3] = pDisplay->GetPaletteB( i ); ++i; p += 4; } } pBmi = QPixmap::fromImage( image ).toWinHBITMAP();
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: AD от Март 04, 2009, 18:21
///
Спасибо большое! Единственное. Я хочу от BitmapInfo совсем отказаться, поэтому у меня QImage - объект внутри нужного класса. И еще один момент. Палитра имеет размер, равный C++ (Qt) pDisplay -> PaletteSize()
И таким образом изменять i, равное width * height, нельзя. Как видоизменить код, исходя из этого ограничения? Указатель на QImage: C++ (Qt) QImage* bitmap; bitmap = new QImage(spSize, QImage::Format_ARGB32);
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: pastor от Март 04, 2009, 18:30
Немного непонятно, pDisplay->PaletteSize() возвращает произведение width * height? Помоему Dendy уже раскрыл вопрос
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: AD от Март 04, 2009, 18:43
Немного непонятно, pDisplay->PaletteSize() возвращает произведение width * height? Помоему Dendy уже раскрыл вопрос
В том то и дело, что pDisplay -> PaletteSize() < width * height! из-за этого выдает сбой. пытался сделать так: C++ (Qt) int i = 0; for(int y=0; y<bitmap -> height(); ++y) { uchar *p = bitmap -> scanLine(y); for(int x=0; x<bitmap -> width(); ++x) { if(i >= pDisplay -> PaletteSize()) i %= pDisplay -> PaletteSize(); p[0] = 255; p[1] = pDisplay -> GetPaletteR(i); p[2] = pDisplay -> GetPaletteG(i); p[3] = pDisplay -> GetPaletteB(i); ++i; p += 4; } } НО тогда выдается такого рода фигня (см. картинку 1). А должна быть картинка такого рода (см. картинку 2)
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: BRE от Март 04, 2009, 19:09
Как устроенна картинка с палитрой: В палитре хранятся цвета в RGB (например палитра из 5 цветов): 0 - QColor( 0, 0, 0 ) 1 - QColor( 255, 255, 255 ) 2 - QColor( 255, 0, 0 ) 3 - QColor( 0, 255, 0 ) 4 - QColor( 0, 0, 255 ) Картинка состоит из индексов в самой палитре (например картинка 7x3): 0 0 1 4 2 3 0 0 3 3 3 2 1 0 1 1 1 1 1 1 1 Чтобы перенести ее в QImage тебе нужно брать индекс цвета, доставать из палитры значения RGB и вставлять в соответствующую позицию QImage. Изменю код Dendy: C++ (Qt) const QSize size( spSize.x, spSize.y ); QImage image( size, QImage::Format_ARGB32 ); for ( int y = 0; y < size.height(); ++y ) { uchar * p = image.scanLine( y ); for ( int x = 0; x < size.width(); ++x ) { // Получаем индекс из исходной картинки int i = indexFromSource( x, y ); p[0] = 255; p[1] = pDisplay->GetPaletteR( i ); p[2] = pDisplay->GetPaletteG( i ); p[3] = pDisplay->GetPaletteB( i ); p += 4; } }
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: pastor от Март 04, 2009, 19:18
А pDisplay что это за тип?
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: AD от Март 04, 2009, 19:22
В доступной палитре, которуая используется, если не ошибаюсь, 256 цветов. В данном случае их 189 (не знаю почему). Какой цвет должен лежать под индексами 190, 191?
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: BRE от Март 04, 2009, 19:24
В доступной палитре, которуая используется, если не ошибаюсь, 256 цветов. В данном случае их 189 (не знаю почему). Какой цвет должен лежать под индексами 190, 191?
Количество цветов в палитре может быть любым, для этого и введен miHeader.biClrUsed. Ты бы побольше кода показал...
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: AD от Март 04, 2009, 19:26
А pDisplay что это за тип?
Не особенно важно. Дело в том, что в проекте используются две библиотеки: Qt and Sahara. 2-ая - это библиотека работы с картографической информацией, изготовлена нашей фирмой. Сейчас задача избавиться от кода зависимости от WINAPI-кода, поэтому и переписываю этот кусок. Заодно решается проблема местоположением виджета (так как в новом варианте нужно только знать ширину и длину виджета).
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: AD от Март 04, 2009, 19:36
Количество цветов в палитре может быть любым, для этого и введен miHeader.biClrUsed. Ты бы побольше кода показал...
Вы не так поняли - библиотека Sahara имеет только определенное количество цветов - максимум их - 256 (если я не ошибаюсь). Больше кода - пожалуйста: C++ (Qt) // Класс набора необходимых Сахаровских классов class SubSahara { protected: SPOINT spSize; SPOINT begSize; GPOINT geoCenter; TImageDrawer* pImageDrawer; MEM256Display* pDisplay; MEM256Device* pDevice; TImageManager* pImageManager; #ifdef Q_WS_WIN BITMAPINFO* pBmi; #endif // Q_WS_WIN bool bInit; ///< флажок инициализировано или нет QImage* bitmap; ///< картинка карты protected: void SaharaInit(int dx, int dy); void SaharaShutdown(); void FillBitmapInfo(); public: SubSahara(int iWidth, int iHeight); ~SubSahara(); #ifdef Q_WS_WIN void Draw(HDC hdc); #endif // Q_WS_WIN void Draw(QPainter* painter); void SetBitmapSize(int Xbeg, int Ybeg, int Xend, int Yend); void SetBitmapSize(int dx, int dy); }; /// Констуктор: все указатели наобъекты инициируются нулевыми указателями SubSahara::SubSahara(int iWidth, int iHeight): bInit(false), pImageDrawer(0), pDisplay(0), pImageManager(0), pDevice(0), bitmap(new QImage(iWidth, iHeight, QImage::Format_ARGB32)) #ifdef Q_WS_WIN , pBmi(static_cast<BITMAPINFO*> (HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256))) #endif // Q_WS_WIN { SaharaInit(iWidth, iHeight); } /// Инициализация указателей на объекты соответствующими классами void SubSahara::SaharaInit(int dx, int dy) { spSize = SPOINT(dx, dy); ResourceLoader *pRL = new FResourceLoader(); pRL -> RegisterBMPResource(&gbPointSymbBitmap, "SYMBPOINT"); pDisplay = new MEM256Display(*pRL); pImageManager = new TImageManager(*pDisplay); pImageDrawer = new TImageDrawer(nIdDCW = pImageManager -> GetFreeId()); pImageDrawer -> SetBoundRect(SRECT(SPOINT(0, 0), spSize)); pImageManager -> RegisterImageStack(pImageDrawer); pDevice = new MEM256Device(*pDisplay, spSize); #ifdef Q_WS_WIN FillBitmapInfo(); #endif // Q_WS_WIN bInit = true; } /// Функция отрисовки карты (для Windows) #ifdef Q_WS_WIN void SubSahara::Draw(HDC hdc) { if(!bInit) return; for(int y = begSize.y; y<spSize.y; ++y) { SetDIBitsToDevice(hdc, ///< handle to DC begSize.x, ///< x-coord of destination upper-left corner y, ///< y-coord of destination upper-left corner spSize.x, ///< source rectangle width 1, ///< source rectangle height 0, ///< x-coord of source lower-left corner 0, ///< y-coord of source lower-left corner 0, ///< first scan line in array 1, ///< number of scan lines ///< array of DIB bits (CONST VOID *)(pDevice->GetSurface() + spSize.x * y), pBmi, ///< bitmap information DIB_RGB_COLORS); } } #endif // Q_WS_WIN /// Функция отрисовки карты void SubSahara::Draw(QPainter* painter) { painter -> drawImage(QPoint(0, 0), *bitmap); } /// Заполнение картинки (для Windows) void SubSahara::FillBitmapInfo() { int i = 0, index = 0; bool flag = false; for(int y=0; y<bitmap -> height(); ++y) { uchar *p = bitmap -> scanLine(y); for(int x=0; x<bitmap -> width(); ++x) { if(i >= pDisplay -> PaletteSize()) { flag = true; i = index % pDisplay -> PaletteSize(); } if(flag) i = index % pDisplay -> PaletteSize(); p[0] = 255; p[1] = pDisplay -> GetPaletteR(i); p[2] = pDisplay -> GetPaletteG(i); p[3] = pDisplay -> GetPaletteB(i); ++i; ++index; p += 4; } } } /* /// Заполнение картинки (для Windows) void SubSahara::FillBitmapInfo() { #ifdef Q_WS_WIN memset(pBmi,0,sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256); pBmi -> bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pBmi -> bmiHeader.biWidth = spSize.x; pBmi -> bmiHeader.biHeight = spSize.y; pBmi -> bmiHeader.biPlanes = 1; pBmi -> bmiHeader.biBitCount = 8; pBmi -> bmiHeader.biCompression = BI_RGB; pBmi -> bmiHeader.biSizeImage = 0; pBmi -> bmiHeader.biClrUsed = pDisplay -> PaletteSize(); pBmi -> bmiHeader.biClrImportant = 0; for(int i = 0; i < pBmi->bmiHeader.biClrUsed; ++i) { pBmi -> bmiColors[i].rgbRed = pDisplay -> GetPaletteR(i); pBmi -> bmiColors[i].rgbGreen = pDisplay -> GetPaletteG(i); pBmi -> bmiColors[i].rgbBlue = pDisplay -> GetPaletteB(i); } #endif // Q_WS_WIN }*/ /// Установка размера картинки void SubSahara::SetBitmapSize(int dx, int dy) { if(spSize.x != dx || spSize.y != dy) { spSize = SPOINT(dx, dy); pImageDrawer -> SetBoundRect(SRECT(SPOINT(0, 0), spSize)); pDevice -> SetSize(spSize); if(bitmap != 0) { delete bitmap; bitmap = 0; } bitmap = new QImage(dx, dy, QImage::Format_ARGB32); FillBitmapInfo(); } } /// Установка размера картинки void SubSahara::SetBitmapSize(int Xbeg, int Ybeg, int Xend, int Yend) { if(spSize.x != Xend || spSize.y != Yend) { spSize = SPOINT(Xend, Yend); begSize = SPOINT(Xbeg, Ybeg); pImageDrawer -> SetBoundRect(SRECT(SPOINT(0, 0), spSize)); pDevice -> SetSize(spSize); if(bitmap != 0) { delete bitmap; bitmap = 0; } bitmap = new QImage(Xend, Yend, QImage::Format_ARGB32); FillBitmapInfo(); } } /// Рисование карты и траектории Сахарой void TrackWidget::paintEvent(QPaintEvent* events) { QPainter painter(this); pSahara -> Refresh(); pSahara -> Draw(&painter); /*#ifdef Q_WS_WIN pSahara -> Draw(painter.paintEngine() -> getDC()); ///< oтрисовка карты #endif // Q_WS_WIN*/ if(measure_flag) { painter.setPen(QPen(Qt::black, 1, Qt::SolidLine)); ///< установка цвета линий QPoint p1(calc_distance -> beginPoint()), p2(calc_distance -> endPoint()); painter.drawLine(p1, p2); } painter.setPen(QPen(Qt::blue, 1, Qt::SolidLine)); ///< установка цвета траектории QWidget::paintEvent(events); }
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: BRE от Март 04, 2009, 19:55
Вы не так поняли - библиотека Sahara имеет только определенное количество цветов - максимум их - 256 (если я не ошибаюсь).
Максиму 256, минимум 1. ;) У класса MEM256Device есть метод GetSurface(), который возвращает указатель на массив точек (индексов). Сразу можно сделать функцию (псевдокод): C++ (Qt) const QSize size( spSize.x, spSize.y ); QImage image( size, QImage::Format_ARGB32 ); for ( int y = 0; y < size.height(); ++y ) { const uchar *scrImage = pDevice->GetSurface() + y * size.width(); uchar * p = image.scanLine( y ); for ( int x = 0; x < size.width(); ++x ) { // Получаем индекс из исходной картинки uchar i = *srcImage++; p[0] = 255; p[1] = pDisplay->GetPaletteR( i ); p[2] = pDisplay->GetPaletteG( i ); p[3] = pDisplay->GetPaletteB( i ); p += 4; } }
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: AD от Март 04, 2009, 21:07
Максиму 256, минимум 1. ;)
У класса MEM256Device есть метод GetSurface(), который возвращает указатель на массив точек (индексов). Сразу можно сделать функцию (псевдокод):
Спасибо. Почти работает! Но картинки получаются что-ли инвертированными. Вот так: (1ый - p[0] = 255) (2ой - p[0] = 0). Придется вручную подбирать цвет или можно решить проблему?
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: BRE от Март 04, 2009, 21:11
Спасибо. Почти работает! Но картинки получаются что-ли инвертированными. Вот так: (1ый - p[0] = 255) (2ой - p[0] = 0). Придется вручную подбирать цвет или можно решить проблему?
Попробуй здесь порядок компонент поменять: C++ (Qt) p[3] = 255; p[2] = pDisplay->GetPaletteR( i ); p[1] = pDisplay->GetPaletteG( i ); p[0] = pDisplay->GetPaletteB( i );
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: AD от Март 04, 2009, 21:31
Еще раз спасибо. Уже сам додумался. 3-й компонент - 255. А раскраска - BGR! Thanks! :))))
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: BRE от Март 04, 2009, 21:34
Еще раз спасибо. Уже сам додумался. 3-й компонент - 255. А раскраска - BGR! Thanks! :))))
Точнее ARGB DWORD 0xAARRGGBB в памяти сохраняется как BB GG RR AA (увеличение адресов --->).
Название: Re: альтернатива BITMAPINFO в QImage
Отправлено: BRE от Март 06, 2009, 11:54
AD, просмотрел я, что QImage и так поддерживает картинки с палитрой. Т.е. можно картинку не переводить в ARGB самому, это может делать сама Qt при отрисовке.
Устанавливаем формат QImage на QImage::Format_Indexed8 и настраиваем палитру: void QImage::setColorTable ( const QVector<QRgb> colors ). Палитру настраиваем из pDisplay->GetPaletteX(...). Данные берем из pDevice->GetSurface(). Подробности в Assistant -> QImage -> Pixel Manipulation. :)
|