1

我正在尝试使用 windows GDI 将 freetype 的字形渲染到窗口。貌似freetype生成的位图是8bit索引位图什么的,因为在它的官方教程example4.cpp中,它使用Qt来渲染字形如下:

error = FT_Render_Glyph(m_face->glyph,
                    FT_RENDER_MODE_NORMAL);

            QImage glyphImage(m_face->glyph->bitmap.buffer,
                m_face->glyph->bitmap.width,
                m_face->glyph->bitmap.rows,
                m_face->glyph->bitmap.pitch,
                QImage::Format_Indexed8);

            /*painter.translate(m_glyphRect.x(),
                m_glyphRect.y());*/

            QVector<QRgb> colorTable;
            for (int i = 0; i < 256; ++i)
                colorTable << qRgba(0, 0, 0, i);
            glyphImage.setColorTable(colorTable);

            painter.drawImage(QPoint(0, 0),
                glyphImage);

所以我尝试使用 gdi 渲染它,如下所示:

BITMAPINFO* pBmi = (BITMAPINFO*)malloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 255);
            BITMAPINFOHEADER &bmh = pBmi->bmiHeader;
            bmh.biSize = sizeof(BITMAPINFOHEADER);
            bmh.biBitCount = 8;
            bmh.biCompression = BI_RGB;
            bmh.biPlanes = 1;
            RGBQUAD* palette = &pBmi->bmiColors[0];
            for (int i = 0; i < 256; ++i) {
                RGBQUAD rgb = {0};
                palette[i] = rgb;
            }

            //assert(pBm->bitmap);
            bmh.biWidth = pBm->bitmap.width;
            bmh.biHeight =  - pBm->bitmap.rows;
            StretchDIBits(hdc, 200, 200, pBm->bitmap.width, pBm->bitmap.rows, 0, 0, pBm->bitmap.width, pBm->bitmap.rows, pBm->bitmap.buffer, 
                pBmi, DIB_PAL_COLORS, SRCCOPY);

然后我尝试使用 GDI+ 进行渲染,但也失败了。

error = FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_NORMAL);
            Bitmap bitmap(pBm->bitmap.width, pBm->bitmap.rows, pBm->bitmap.pitch, PixelFormat8bppIndexed, pBm->bitmap.buffer);
            //Bitmap bitmap(pBm->bitmap.width, pBm->bitmap.rows, 64, PixelFormat8bppIndexed, pBm->bitmap.buffer);
            ColorPalette* pal = (ColorPalette*)malloc(sizeof(ColorPalette) + 255 * sizeof(ARGB));
            pal->Flags = PaletteFlagsGrayScale;
            pal->Count = 256;
            for (int i = 0; i <= 255; i++) {
                pal->Entries[i] = Color::MakeARGB(i, 0, 0, 0);
            }
            bitmap.SetPalette(pal);
            Graphics graphics(hdc);
            graphics.DrawImage(&bitmap, 100, 100);

您能否告诉我,如何使用 GDI/GDI+ 在 Windows 中呈现每像素 8 位索引位图。谢谢。

4

2 回答 2

3

就像这里的注释一样:

        hdc = BeginPaint(hWnd, &ps);

        assert(Draw());

        FT_GlyphSlot &pBm = m_face->glyph;

        //output by console
        {
            printf("\n");
            for (int j = 0; j < pBm->bitmap.rows; j++) {
                printf("\n");
                for (int i = 0; i < pBm->bitmap.width; i++) 
                    printf("%2x", pBm->bitmap.buffer[j * pBm->bitmap.width + i]);
            }
        }

        //output by gdi+
        {
            Bitmap *pBitmap = NULL;
            LPBYTE pBuffer = NULL;      
            int stride = (pBm->bitmap.pitch + 3) / 4 * 4;
            if (stride != pBm->bitmap.pitch)
            {
                pBuffer = new BYTE[stride * pBm->bitmap.rows];
                memset(pBuffer, 0, stride * pBm->bitmap.rows);
                for (int i = 0; i < pBm->bitmap.rows; i++)
                    for (int j = 0; j < pBm->bitmap.width; j++)
                        pBuffer[i * stride + j] = pBm->bitmap.buffer[i * pBm->bitmap.width + j];
            } else
            {
                pBuffer = pBm->bitmap.buffer;
            }
            pBitmap = new Bitmap(pBm->bitmap.width, pBm->bitmap.rows, stride, PixelFormat8bppIndexed, pBuffer);
            ColorPalette *pPalette = (ColorPalette*)malloc(sizeof(ColorPalette) + 255 * sizeof(ARGB));
            pPalette->Count = 256;
            pPalette->Flags = PaletteFlagsGrayScale;
            ARGB* pColor = &pPalette->Entries[0];
            for (int i = 0; i < 256; i++)
                pColor[i] = Color::MakeARGB(i, 0x00, 0x00, 0x00);
            assert(pBitmap->GetLastStatus() == Ok);
            pBitmap->SetPalette(pPalette);
            assert(pBitmap->GetLastStatus() == Ok);
            Graphics graphics(hdc);
            graphics.DrawImage(pBitmap, 300, 300);

            free(pPalette);
            delete pBitmap;

            //draw with gdi
            {
                BITMAPINFO* pBmi = (BITMAPINFO*)malloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 255);
                memset(pBmi, 0, sizeof(BITMAPINFO));
                BITMAPINFOHEADER &bmh = pBmi->bmiHeader;
                bmh.biSize = sizeof(BITMAPINFOHEADER);
                bmh.biBitCount = 8;
                bmh.biCompression = BI_RGB;
                bmh.biPlanes = 1;
                RGBQUAD* palette = &pBmi->bmiColors[0];
                for (int i = 0; i < 256; ++i) 
                {
                    RGBQUAD rgb = {0};
                    rgb.rgbRed =  ~i;
                    rgb.rgbGreen =  ~i;
                    rgb.rgbBlue =  ~i;
                    palette[i] = rgb;
                }
                bmh.biWidth = stride;
                bmh.biHeight =  - pBm->bitmap.rows;
                StretchDIBits(hdc, 200, 200, stride, pBm->bitmap.rows, 0, 0, stride, pBm->bitmap.rows, pBuffer, 
                    pBmi, DIB_RGB_COLORS, SRCCOPY);

                if (pBmi)
                    free(pBmi);

                if (pBuffer != pBm->bitmap.buffer)
                    delete [] pBuffer;

                /*bmh.biWidth = pBm->bitmap.width;
                bmh.biHeight =  - pBm->bitmap.rows;
                StretchDIBits(hdc, 200, 200, pBm->bitmap.width, pBm->bitmap.rows, 0, 0, pBm->bitmap.width, pBm->bitmap.rows, pBm->bitmap.buffer, 
                    pBmi, DIB_PAL_COLORS, SRCCOPY);*/
            }

        }
        EndPaint(hWnd, &ps);

两点:
1)正如 Mark Randsom 和 paulsm4 所说,调色板是强制性的。
2) 对齐 4。

于 2013-01-18T05:36:36.857 回答
1

您给出的 Qt 示例创建了一个全黑的调色板,透明度随强度而变化。您与 GDI 一起使用的调色板是全黑的,句号。你需要改变颜色。

于 2013-01-18T05:16:30.187 回答