Exemple #1
0
void ui_menu::render_triangle(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param)
{
	int halfwidth = dest.width() / 2;
	int height = dest.height();
	int x, y;

	// start with all-transparent
	dest.fill(rgb_t(0x00,0x00,0x00,0x00));

	// render from the tip to the bottom
	for (y = 0; y < height; y++)
	{
		int linewidth = (y * (halfwidth - 1) + (height / 2)) * 255 * 2 / height;
		UINT32 *target = &dest.pix32(y, halfwidth);

		// don't antialias if height < 12
		if (dest.height() < 12)
		{
			int pixels = (linewidth + 254) / 255;
			if (pixels % 2 == 0) pixels++;
			linewidth = pixels * 255;
		}

		// loop while we still have data to generate
		for (x = 0; linewidth > 0; x++)
		{
			int dalpha;

			// first column we only consume one pixel
			if (x == 0)
			{
				dalpha = MIN(0xff, linewidth);
				target[x] = rgb_t(dalpha,0xff,0xff,0xff);
			}

			// remaining columns consume two pixels, one on each side
			else
			{
				dalpha = MIN(0x1fe, linewidth);
				target[x] = target[-x] = rgb_t(dalpha/2,0xff,0xff,0xff);
			}

			// account for the weight we consumed */
			linewidth -= dalpha;
		}
	}
}
Exemple #2
0
bool sdl_osd_interface::font_get_bitmap(osd_font font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs)
{
#if !(SDLMAME_SDL2)
	TTF_Font *ttffont;
	SDL_Surface *drawsurf;
	SDL_Color fcol = { 0xff, 0xff, 0xff };
	UINT16 ustr[16];

	ttffont = (TTF_Font *)font;

	memset(ustr,0,sizeof(ustr));
	ustr[0] = (UINT16)chnum;
	drawsurf = TTF_RenderUNICODE_Solid(ttffont, ustr, fcol);

	// was nothing returned?
	if (drawsurf)
	{
		// allocate a MAME destination bitmap
		bitmap.allocate(drawsurf->w, drawsurf->h);

		// copy the rendered character image into it
		for (int y = 0; y < bitmap.height(); y++)
		{
			UINT32 *dstrow = &bitmap.pix32(y);
			UINT8 *srcrow = (UINT8 *)drawsurf->pixels;

			srcrow += (y * drawsurf->pitch);

			for (int x = 0; x < drawsurf->w; x++)
			{
				dstrow[x] = srcrow[x] ? rgb_t(0xff,0xff,0xff,0xff) : rgb_t(0x00,0xff,0xff,0xff);
			}
		}

		// what are these?
		xoffs = yoffs = 0;
		width = drawsurf->w;

		SDL_FreeSurface(drawsurf);
	}

	return bitmap.valid();
#else
	return false;
#endif
}
Exemple #3
0
HRESULT SaveBitmap2(bitmap_argb32 &bitmap, const WCHAR *filename)
{
	HRESULT result;

	// Convert the bitmap into a form we understand and save it
	std::unique_ptr<UINT32> pBitmap(new UINT32[bitmap.width() * bitmap.height()]);
	for (int y = 0; y < bitmap.height(); y++)
	{
		UINT32* pRow = pBitmap.get() + (y * bitmap.width());
		for (int x = 0; x < bitmap.width(); x++)
		{
			UINT32 pixel = bitmap.pix32(y, x);
			pRow[x] = (pixel == 0xFFFFFFFF) ? rgb_t(0xFF, 0x00, 0x00, 0x00) : rgb_t(0xFF, 0xFF, 0xFF, 0xFF);
		}
	}

	ComPtr<IWICImagingFactory> wicFactory;
	HR_RETHR(CoCreateInstance(
		CLSID_WICImagingFactory,
		nullptr,
		CLSCTX_INPROC_SERVER,
		__uuidof(IWICImagingFactory),
		(void**)&wicFactory));

	// Save bitmap
	ComPtr<IWICBitmap> bmp2 = nullptr;
	wicFactory->CreateBitmapFromMemory(
		bitmap.width(),
		bitmap.height(),
		GUID_WICPixelFormat32bppRGBA,
		bitmap.width() * sizeof(UINT32),
		bitmap.width() * bitmap.height() * sizeof(UINT32),
		(BYTE*)pBitmap.get(),
		&bmp2);

	SaveBitmap(bmp2.Get(), GUID_WICPixelFormat32bppRGBA, filename);

	return S_OK;
}
Exemple #4
0
bool sdl_osd_interface::font_get_bitmap(osd_font font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs)
{
   UniChar uni_char;
   CGGlyph glyph;
   CTFontRef ct_font = (CTFontRef)font;
   const CFIndex count = 1;
   CGRect bounding_rect, success_rect;
   CGContextRef context_ref;

   if( chnum == ' ' )
   {
      uni_char = 'n';
      CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count );
      success_rect = CTFontGetBoundingRectsForGlyphs( ct_font, kCTFontDefaultOrientation, &glyph, &bounding_rect, count );
      uni_char = chnum;
      CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count );
   }
   else
   {
      uni_char = chnum;
      CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count );
      success_rect = CTFontGetBoundingRectsForGlyphs( ct_font, kCTFontDefaultOrientation, &glyph, &bounding_rect, count );
   }

   if( CGRectEqualToRect( success_rect, CGRectNull ) == false )
   {
      size_t bitmap_width;
      size_t bitmap_height;

      bitmap_width = ceilf(bounding_rect.size.width * EXTRA_WIDTH);
      bitmap_width = bitmap_width == 0 ? 1 : bitmap_width;

      bitmap_height = ceilf( (CTFontGetAscent(ct_font) + CTFontGetDescent(ct_font) + CTFontGetLeading(ct_font)) * EXTRA_HEIGHT);

      xoffs = yoffs = 0;
      width = bitmap_width;

      size_t bits_per_component;
      CGColorSpaceRef color_space;
      CGBitmapInfo bitmap_info = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst;

      color_space = CGColorSpaceCreateDeviceRGB();
      bits_per_component = 8;

      bitmap.allocate(bitmap_width, bitmap_height);

      context_ref = CGBitmapContextCreate( bitmap.raw_pixptr(0), bitmap_width, bitmap_height, bits_per_component, bitmap.rowpixels()*4, color_space, bitmap_info );

      if( context_ref != NULL )
      {
         CGFontRef font_ref;
         font_ref = CTFontCopyGraphicsFont( ct_font, NULL );
         CGContextSetTextPosition(context_ref, -bounding_rect.origin.x*EXTRA_WIDTH, CTFontGetDescent(ct_font)+CTFontGetLeading(ct_font) );
         CGContextSetRGBFillColor(context_ref, 1.0, 1.0, 1.0, 1.0);
         CGContextSetFont( context_ref, font_ref );
         CGContextSetFontSize( context_ref, POINT_SIZE );
         CGContextShowGlyphs( context_ref, &glyph, count );
         CGFontRelease( font_ref );
         CGContextRelease( context_ref );
      }

      CGColorSpaceRelease( color_space );
   }

   return bitmap.valid();
}
Exemple #5
0
	virtual bool get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, std::int32_t &width, std::int32_t &xoffs, std::int32_t &yoffs) override
	{
		const int MEM_ALIGN_CONST = 31;
		const int BITMAP_PAD = 50;

		HRESULT result;
		UINT cbData;
		BYTE* pixels = nullptr;

		ComPtr<ID2D1BitmapRenderTarget>     target;
		ComPtr<ID2D1SolidColorBrush>        pWhiteBrush;
		ComPtr<IWICBitmap>                  wicBitmap;
		ComPtr<IWICBitmapLock>              lock;

		ComPtr<IDWriteFontFace> face;
		HR_RET0(m_font->CreateFontFace(face.GetAddressOf()));

		// get the GDI metrics
		DWRITE_FONT_METRICS gdi_metrics;
		HR_RET0(face->GetGdiCompatibleMetrics(
			m_fontEmHeightInDips,
			1.0f,
			nullptr,
			&gdi_metrics));

		FontDimensionFactory fdf(gdi_metrics.designUnitsPerEm, m_fontEmHeightInDips);

		UINT32 tempChar = chnum;
		UINT16 glyphIndex;
		HR_RET0(face->GetGlyphIndicesW(&tempChar, 1, &glyphIndex));

		// get the width of this character
		DWRITE_GLYPH_METRICS glyph_metrics = { 0 };
		HR_RET0(face->GetGdiCompatibleGlyphMetrics(
			m_fontEmHeightInDips,
			1.0f,
			nullptr,
			FALSE,
			&glyphIndex,
			1,
			&glyph_metrics));

		// The height is the ascent added to the descent
		// By definition, the Em is equal to Cell Height minus Internal Leading (topSide bearing).
		//auto cellheight = fdf.FromDesignUnit(gdi_metrics.ascent + gdi_metrics.descent + gdi_metrics.);
		auto ascent = fdf.FromDesignUnit(gdi_metrics.ascent);
		auto descent = fdf.FromDesignUnit(gdi_metrics.descent);
		auto charHeight = ascent + descent;

		auto abc = fdf.CreateAbcWidths(
			glyph_metrics.advanceWidth,
			glyph_metrics.leftSideBearing,
			glyph_metrics.rightSideBearing);

		width = abc.abcA().Dips() + abc.abcB().Dips() + abc.abcC().Dips();

		// determine desired bitmap size
		int bmwidth = (BITMAP_PAD + abc.abcA().Dips() + abc.abcB().Dips() + abc.abcC().Dips() + BITMAP_PAD + MEM_ALIGN_CONST) & ~MEM_ALIGN_CONST;
		int bmheight = BITMAP_PAD + charHeight.Dips() + BITMAP_PAD;

		// GUID_WICPixelFormat8bppAlpha is 8 bits per pixel
		const REFWICPixelFormatGUID     source_bitmap_wic_format = GUID_WICPixelFormat8bppAlpha;
		const DXGI_FORMAT               source_bitmap_dxgi_format = DXGI_FORMAT_A8_UNORM;
		const D2D1_ALPHA_MODE           source_bitmap_d2d_alpha_mode = D2D1_ALPHA_MODE_STRAIGHT;

		// describe the bitmap we want
		HR_RET0(m_wicFactory->CreateBitmap(
			bmwidth,
			bmheight,
			source_bitmap_wic_format,
			WICBitmapCacheOnLoad,
			wicBitmap.GetAddressOf()));

		D2D1_RENDER_TARGET_PROPERTIES targetProps;
		targetProps = D2D1::RenderTargetProperties();
		targetProps.pixelFormat = D2D1::PixelFormat(source_bitmap_dxgi_format, source_bitmap_d2d_alpha_mode);

		// create a DIB to render to
		HR_RET0(this->m_d2dfactory->CreateWicBitmapRenderTarget(
			wicBitmap.Get(),
			&targetProps,
			reinterpret_cast<ID2D1RenderTarget**>(target.GetAddressOf())));

		target->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);

		// Create our brush
		HR_RET0(target->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), pWhiteBrush.GetAddressOf()));

		// Signal the start of the frame
		target->BeginDraw();

		// clear the bitmap
		// In the alpha mask, it will look like 0x00 per pixel
		target->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f));

		// now draw the character
		DWRITE_GLYPH_RUN run = { nullptr };
		DWRITE_GLYPH_OFFSET offsets;
		offsets.advanceOffset = 0;
		offsets.ascenderOffset = 0;
		float advanceWidth = abc.advanceWidth().Dips();

		run.fontEmSize = m_fontEmHeightInDips;
		run.fontFace = face.Get();
		run.glyphCount = 1;
		run.glyphIndices = &glyphIndex;
		run.glyphAdvances = &advanceWidth;
		run.glyphOffsets = &offsets;

		auto baseline_origin = D2D1::Point2F(BITMAP_PAD + abc.abcA().Dips() + 1, BITMAP_PAD + ascent.Dips());
		target->DrawGlyphRun(
			baseline_origin,
			&run,
			pWhiteBrush.Get(),
			DWRITE_MEASURING_MODE_GDI_CLASSIC);

		HR_RET0(target->EndDraw());

#ifdef DWRITE_DEBUGGING
		// Save to file for debugging
		SaveBitmap(wicBitmap.Get(), GUID_WICPixelFormatBlackWhite, L"C:\\temp\\ddraw_step1.bmp");
#endif

		// characters are expected to be full-height
		rectangle actbounds;
		actbounds.min_y = BITMAP_PAD;
		actbounds.max_y = BITMAP_PAD + charHeight.Dips() - 1;

		// Lock the bitmap and get the data pointer
		WICRect rect = { 0, 0, bmwidth, bmheight };
		HR_RET0(wicBitmap->Lock(&rect, WICBitmapLockRead, lock.GetAddressOf()));
		HR_RET0(lock->GetDataPointer(&cbData, static_cast<BYTE**>(&pixels)));

		// determine the actual left of the character
		for (actbounds.min_x = 0; actbounds.min_x < bmwidth; actbounds.min_x++)
		{
			BYTE *offs = pixels + actbounds.min_x;
			UINT8 summary = 0;
			for (int y = 0; y < bmheight; y++)
				summary |= offs[y * bmwidth];
			if (summary != 0)
			{
				break;
			}
		}

		// determine the actual right of the character
		// Start from the right edge, and move in until we find a pixel
		for (actbounds.max_x = bmwidth - 1; actbounds.max_x >= 0; actbounds.max_x--)
		{
			BYTE *offs = pixels + actbounds.max_x;
			UINT8 summary = 0;

			// Go through the entire column and build a summary
			for (int y = 0; y < bmheight; y++)
				summary |= offs[y * bmwidth];
			if (summary != 0)
			{
				break;
			}
		}

		// allocate a new bitmap
		if (actbounds.max_x >= actbounds.min_x && actbounds.max_y >= actbounds.min_y)
		{
			bitmap.allocate(actbounds.max_x + 1 - actbounds.min_x, actbounds.max_y + 1 - actbounds.min_y);

			// copy the bits into it
			for (int y = 0; y < bitmap.height(); y++)
			{
				UINT32 *dstrow = &bitmap.pix32(y);
				UINT8 *srcrow = &pixels[(y + actbounds.min_y) * bmwidth];
				for (int x = 0; x < bitmap.width(); x++)
				{
					int effx = x + actbounds.min_x;
					dstrow[x] = rgb_t(srcrow[effx], 0xff, 0xff, 0xff);
				}
			}

			// set the final offset values
			xoffs = actbounds.min_x - (BITMAP_PAD + abc.abcA().Dips());
			yoffs = actbounds.max_y - (BITMAP_PAD + ascent.Dips());

#ifdef DWRITE_DEBUGGING
			SaveBitmap2(bitmap, L"C:\\temp\\dwrite_final.bmp");
#endif
		}

		BOOL success = bitmap.valid();

#ifdef DWRITE_DEBUGGING
		osd_printf_debug(
			"dwr: %s, c'%S' w%i x%i y%i asc%i dsc%i a%ib%ic%i\n",
			success ? "Success" : "Error",
			(WCHAR*)&chnum,
			width,
			xoffs,
			yoffs,
			ascent.Dips(),
			descent.Dips(),
			abc.abcA().Dips(),
			abc.abcB().Dips(),
			abc.abcC().Dips());
#endif
		return success;
	}
Exemple #6
0
inline int pixel_is_set(bitmap_argb32 &bitmap, int y, int x)
{
	return (bitmap.pix32(y, x) & 0xffffff) == 0;
}
Exemple #7
0
static bool bitmap_to_chars(bitmap_argb32 &bitmap, render_font &font)
{
	// loop over rows
	int rowstart = 0;
	while (rowstart < bitmap.height())
	{
		// find the top of the row
		for ( ; rowstart < bitmap.height(); rowstart++)
			if (pixel_is_set(bitmap, rowstart, 0))
				break;
		if (rowstart >= bitmap.height())
			break;

		// find the bottom of the row
		int rowend;
		for (rowend = rowstart + 1; rowend < bitmap.height(); rowend++)
			if (!pixel_is_set(bitmap, rowend, 0))
			{
				rowend--;
				break;
			}

		// find the baseline
		int baseline;
		for (baseline = rowstart; baseline <= rowend; baseline++)
			if (pixel_is_set(bitmap, baseline, 1))
				break;
		if (baseline > rowend)
		{
			fprintf(stderr, "No baseline found between rows %d-%d\n", rowstart, rowend);
			break;
		}

		// set or confirm the height
		if (font.height == 0)
		{
			font.height = rowend - rowstart + 1;
			font.yoffs = baseline - rowend;
		}
		else
		{
			if (font.height != rowend - rowstart + 1)
			{
				fprintf(stderr, "Inconsistent font height at rows %d-%d\n", rowstart, rowend);
				break;
			}
			if (font.yoffs != baseline - rowend)
			{
				fprintf(stderr, "Inconsistent baseline at rows %d-%d\n", rowstart, rowend);
				break;
			}
		}

		// decode the starting character
		int chstart = 0;
		for (int x = 0; x < 4; x++)
			for (int y = 0; y < 4; y++)
				chstart = (chstart << 1) | pixel_is_set(bitmap, rowstart + y, 2 + x);

		// print info
//      printf("Row %d-%d, baseline %d, character start %X\n", rowstart, rowend, baseline, chstart);

		// scan the column to find characters
		int colstart = 0;
		while (colstart < bitmap.width())
		{
			render_font_char &ch = font.chars[chstart];

			// find the start of the character
			for ( ; colstart < bitmap.width(); colstart++)
				if (pixel_is_set(bitmap, rowend + 2, colstart))
					break;
			if (colstart >= bitmap.width())
				break;

			// find the end of the character
			int colend;
			for (colend = colstart + 1; colend < bitmap.width(); colend++)
				if (!pixel_is_set(bitmap, rowend + 2, colend))
				{
					colend--;
					break;
				}

			// skip char which code is already registered
			if (ch.width <= 0)
			{
				// print info
//              printf("  Character %X - width = %d\n", chstart, colend - colstart + 1);

				// allocate a bitmap
				ch.bitmap = global_alloc(bitmap_argb32(colend - colstart + 1, font.height));

				// plot the character
				for (int y = rowstart; y <= rowend; y++)
					for (int x = colstart; x <= colend; x++)
						ch.bitmap->pix32(y - rowstart, x - colstart) = pixel_is_set(bitmap, y, x) ? 0xffffffff : 0x00000000;

				// set the character parameters
				ch.width = colend - colstart + 1;
				ch.xoffs = 0;
				ch.yoffs = font.yoffs;
				ch.bmwidth = ch.bitmap->width();
				ch.bmheight = ch.bitmap->height();
			}

			// next character
			chstart++;
			colstart = colend + 1;
		}

		// next row
		rowstart = rowend + 1;
	}

	// return non-zero (TRUE) if we errored
	return (rowstart < bitmap.height());
}
Exemple #8
0
bool osd_font_windows::get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs)
{
    // create a dummy DC to work with
    HDC dummyDC = CreateCompatibleDC(NULL);
    HGDIOBJ oldfont = SelectObject(dummyDC, m_font);

    // get the text metrics
    TEXTMETRIC metrics = { 0 };
    GetTextMetrics(dummyDC, &metrics);

    // get the width of this character
    ABC abc;
    if (!GetCharABCWidths(dummyDC, chnum, chnum, &abc))
    {
        abc.abcA = 0;
        abc.abcC = 0;
        GetCharWidth32(dummyDC, chnum, chnum, reinterpret_cast<LPINT>(&abc.abcB));
    }
    width = abc.abcA + abc.abcB + abc.abcC;

    // determine desired bitmap size
    int bmwidth = (50 + abc.abcA + abc.abcB + abc.abcC + 50 + 31) & ~31;
    int bmheight = 50 + metrics.tmHeight + 50;

    // describe the bitmap we want
    BYTE bitmapinfodata[sizeof(BITMAPINFOHEADER)+2 * sizeof(RGBQUAD)] = { 0 };
    BITMAPINFO &info = *reinterpret_cast<BITMAPINFO *>(bitmapinfodata);
    info.bmiHeader.biSize = sizeof(info.bmiHeader);
    info.bmiHeader.biWidth = bmwidth;
    info.bmiHeader.biHeight = -bmheight;
    info.bmiHeader.biPlanes = 1;
    info.bmiHeader.biBitCount = 1;
    info.bmiHeader.biCompression = BI_RGB;
    info.bmiHeader.biSizeImage = 0;
    info.bmiHeader.biXPelsPerMeter = GetDeviceCaps(dummyDC, HORZRES) / GetDeviceCaps(dummyDC, HORZSIZE);
    info.bmiHeader.biYPelsPerMeter = GetDeviceCaps(dummyDC, VERTRES) / GetDeviceCaps(dummyDC, VERTSIZE);
    info.bmiHeader.biClrUsed = 0;
    info.bmiHeader.biClrImportant = 0;
    RGBQUAD col1 = info.bmiColors[0];
    RGBQUAD col2 = info.bmiColors[1];
    col1.rgbBlue = col1.rgbGreen = col1.rgbRed = 0x00;
    col2.rgbBlue = col2.rgbGreen = col2.rgbRed = 0xff;

    // create a DIB to render to
    BYTE *bits;
    HBITMAP dib = CreateDIBSection(dummyDC, &info, DIB_RGB_COLORS, reinterpret_cast<VOID **>(&bits), NULL, 0);

    if (dib)
    {
        HGDIOBJ oldbitmap = SelectObject(dummyDC, dib);

        // clear the bitmap
        int rowbytes = bmwidth / 8;
        memset(bits, 0, rowbytes * bmheight);

        // now draw the character
        WCHAR tempchar = chnum;
        SetTextColor(dummyDC, RGB(0xff, 0xff, 0xff));
        SetBkColor(dummyDC, RGB(0x00, 0x00, 0x00));
        ExtTextOutW(dummyDC, 50 + abc.abcA, 50, ETO_OPAQUE, NULL, &tempchar, 1, NULL);

        // characters are expected to be full-height
        rectangle actbounds;
        actbounds.min_y = 50;
        actbounds.max_y = 50 + metrics.tmHeight - 1;

        // determine the actual left of the character
        for (actbounds.min_x = 0; actbounds.min_x < rowbytes; actbounds.min_x++)
        {
            BYTE *offs = bits + actbounds.min_x;
            UINT8 summary = 0;
            for (int y = 0; y < bmheight; y++)
                summary |= offs[y * rowbytes];
            if (summary != 0)
            {
                actbounds.min_x *= 8;
                if (!(summary & 0x80)) actbounds.min_x++;
                if (!(summary & 0xc0)) actbounds.min_x++;
                if (!(summary & 0xe0)) actbounds.min_x++;
                if (!(summary & 0xf0)) actbounds.min_x++;
                if (!(summary & 0xf8)) actbounds.min_x++;
                if (!(summary & 0xfc)) actbounds.min_x++;
                if (!(summary & 0xfe)) actbounds.min_x++;
                break;
            }
        }

        // determine the actual right of the character
        for (actbounds.max_x = rowbytes - 1; actbounds.max_x >= 0; actbounds.max_x--)
        {
            BYTE *offs = bits + actbounds.max_x;
            UINT8 summary = 0;
            for (int y = 0; y < bmheight; y++)
                summary |= offs[y * rowbytes];
            if (summary != 0)
            {
                actbounds.max_x *= 8;
                if (summary & 0x7f) actbounds.max_x++;
                if (summary & 0x3f) actbounds.max_x++;
                if (summary & 0x1f) actbounds.max_x++;
                if (summary & 0x0f) actbounds.max_x++;
                if (summary & 0x07) actbounds.max_x++;
                if (summary & 0x03) actbounds.max_x++;
                if (summary & 0x01) actbounds.max_x++;
                break;
            }
        }

        // allocate a new bitmap
        if (actbounds.max_x >= actbounds.min_x && actbounds.max_y >= actbounds.min_y)
        {
            bitmap.allocate(actbounds.max_x + 1 - actbounds.min_x, actbounds.max_y + 1 - actbounds.min_y);

            // copy the bits into it
            for (int y = 0; y < bitmap.height(); y++)
            {
                UINT32 *dstrow = &bitmap.pix32(y);
                UINT8 *srcrow = &bits[(y + actbounds.min_y) * rowbytes];
                for (int x = 0; x < bitmap.width(); x++)
                {
                    int effx = x + actbounds.min_x;
                    dstrow[x] = ((srcrow[effx / 8] << (effx % 8)) & 0x80) ? rgb_t(0xff, 0xff, 0xff, 0xff) : rgb_t(0x00, 0xff, 0xff, 0xff);
                }
            }

            // set the final offset values
            xoffs = actbounds.min_x - (50 + abc.abcA);
            yoffs = actbounds.max_y - (50 + metrics.tmAscent);
        }

        // de-select the font and release the DC
        SelectObject(dummyDC, oldbitmap);
        DeleteObject(dib);
    }

    SelectObject(dummyDC, oldfont);
    DeleteDC(dummyDC);
    return bitmap.valid();
}