// Internal function to fill a rectangle with a colour void MHIDLA::DrawRect(int x, int y, int width, int height, MHRgba colour) { QRgb qColour = qRgba(colour.red(), colour.green(), colour.blue(), colour.alpha()); // Constrain the drawing within the image. if (x < 0) { width += x; x = 0; } if (y < 0) { height += y; y = 0; } if (width <= 0 || height <= 0) return; int imageWidth = m_image.width(), imageHeight = m_image.height(); if (x+width > imageWidth) width = imageWidth - x; if (y+height > imageHeight) height = imageHeight - y; if (width <= 0 || height <= 0) return; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { m_image.setPixel(x+j, y+i, qColour); } } }
// Draw a rectangle. This is complicated if we want to get transparency right. void MHIContext::DrawRect(int xPos, int yPos, int width, int height, MHRgba colour) { if (colour.alpha() == 0 || height == 0 || width == 0) return; // Fully transparent QRgb qColour = qRgba(colour.red(), colour.green(), colour.blue(), colour.alpha()); int scaledWidth = SCALED_X(width); int scaledHeight = SCALED_Y(height); QImage qImage(scaledWidth, scaledHeight, QImage::Format_ARGB32); for (int i = 0; i < scaledHeight; i++) { for (int j = 0; j < scaledWidth; j++) { qImage.setPixel(j, i, qColour); } } AddToDisplay(qImage, SCALED_X(xPos), SCALED_Y(yPos)); }
// Draw a line of text in the given position within the image. // It would be nice to be able to use TTFFont for this but it doesn't provide // what we want. void MHIText::AddText(int x, int y, const QString &str, MHRgba colour) { if (!m_parent->IsFaceLoaded()) return; FT_Face face = m_parent->GetFontFace(); FT_Error error = FT_Set_Char_Size(face, 0, Point2FT(m_fontsize), FONT_WIDTHRES, FONT_HEIGHTRES); // X positions are computed to 64ths and rounded. // Y positions are in pixels int posX = Point2FT(x); int pixelY = y; FT_Bool useKerning = FT_HAS_KERNING(face); FT_UInt previous = 0; int len = str.length(); for (int n = 0; n < len; n++) { // Load the glyph. QChar ch = str[n]; FT_UInt glyphIndex = FT_Get_Char_Index(face, ch.unicode()); if (glyphIndex == 0) { previous = 0; continue; } if (useKerning && previous != 0) { FT_Vector delta; FT_Get_Kerning(face, previous, glyphIndex, FT_KERNING_DEFAULT, &delta); posX += delta.x; } error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER); if (error) continue; // ignore errors FT_GlyphSlot slot = face->glyph; if (slot->format != FT_GLYPH_FORMAT_BITMAP) continue; // Problem if ((enum FT_Pixel_Mode_)slot->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY) continue; unsigned char *source = slot->bitmap.buffer; // Get the origin for the bitmap int baseX = FT2Point(posX) + slot->bitmap_left; int baseY = pixelY - slot->bitmap_top; // Copy the bitmap into the image. for (int i = 0; i < slot->bitmap.rows; i++) { for (int j = 0; j < slot->bitmap.width; j++) { int greyLevel = source[j]; // Set the pixel to the specified colour but scale its // brightness according to the grey scale of the pixel. int red = colour.red(); int green = colour.green(); int blue = colour.blue(); int alpha = colour.alpha() * greyLevel / slot->bitmap.num_grays; int xBit = j + baseX; int yBit = i + baseY; // The bits ought to be inside the bitmap but // I guess there's the possibility // that rounding might put it outside. if (xBit >= 0 && xBit < m_width && yBit >= 0 && yBit < m_height) { m_image.setPixel(xBit, yBit, qRgba(red, green, blue, alpha)); } } source += slot->bitmap.pitch; } posX += slot->advance.x; previous = glyphIndex; } }