I have some legacy MFC apps, and I'd like to use the Cairo drawing engine to add some charts and graphs.
I'm searching for a small example of how to get that to work. Basically, once I've created a PNG or GIF file, how do I get that show up in an MFC CView window?
My google-fu is not finding any good clues.
From my demo samples,
// cairo_surface_t *surface;
// cairo_t *cr;
// surface = call_win32_surface_create_with_dib_T(CAIRO_FORMAT_ARGB32, 240, 80);
// cr = call_create_T (surface);
// call_surface_write_to_png_T (surface, "hello.png");
HDC src = call_win32_surface_get_dc_T(surface); // <--------
BitBlt(dest, 0, 0, 240, 80, src, 0,0, SRCCOPY); // <--------
Assuming that you already have a surface you can use something like the above sample.dest is the HDC handle to the window you want to render the cairo surface.
Update: CView::OnDraw()
You should implement the OnDraw() method for your CView (inherited?) class.
You can use the pDC pointer to draw the cairo surface, ie:
pDC->BitBlt(0, 0, 240, 80, src, 0,0, SRCCOPY); // "HDC src" is mentioned above
Related
So i have been trying to repaint a bitmap programatically when user pressed a button with ExtFloodFill with the code below
CDC* cdc = GetDlgItem(IDC_MAP_STATIC)->GetDC(); // Get the CStatic that contains the bitmap
cdc->SetDCBrushColor(COLOR_SKYBLUE); // constant for #00EEEE
SetDCBrushColor((HDC)cdc, COLOR_SKYBLUE); // Trying to change the cdc brush color
// Just for debugging, i have inspected it and the value is the same with the COLOR_SKYBLUE value
COLORREF cr = cdc->GetDCBrushColor();
cdc->ExtFloodFill(x,cdc->GetCurrentPosition().y+y, RGB(0, 0, 0), FLOODFILLBORDER);
But everytime that i call ExtFloodFill the FloodFill will only fill the area with white color and as per the doc
Fills an area of the display surface with the current brush.
I tried to change the current CDC brush color with the color skyblue. But it doesn't work at all.
IDC_MAP_STATIC is an usual CStatic object. I'm not using a subclassed CStatic for it.
So where did i do wrong that it caused the ExtFloodFill to keep Flood-filling my bitmap with white not skyblue?
Nevermind, solved it right away with this snippet. I don't know why but when i set the brush color using SetDCBrushColor it doesn't change the selected brush. So with codes based from this article i tried to declare a new brush and select it before i tried to FloodFill it
CDC* cdc = GetDlgItem(IDC_MAP_STATIC)->GetDC();
CBrush cb(RGB(255, 0, 0)); //Make a new CBrush (Red)
cdc->SelectObject(&cb); //Assign the CBrush to the CDC
cdc->ExtFloodFill(x,y, RGB(0, 0, 0), FLOODFILLBORDER);
DeleteObject(cb);
ReleaseDC(cdc);
http://msdn.microsoft.com/en-us/library/sa8ahz7h(v=vs.80).aspx
//Border
CPen pen;
pen.CreatePen(PS_DASH, 20, RGB(0, 0, 0));
CPen* penOld = dc.SelectObject(&pen);
dc.Rectangle(rect);
dc.FillRect(rect, &brush);
How does this code work? It draws a rectangle and then a border around it. I just can't get my head around it.
When you ask the device context to draw a rectangle, it will use the current Pen.
You can set the current Pen, Brush, clipping region or whatever using the SelectObject() method. You're basically saying "use this Pen from now on".
SelectObject() also returns the item it was using before, so that it doesn't get lost and leak memory, and you can put it back later if you want. This is why penOld is being saved to a variable in your code. It will probably be selected back again later on.
CPen pen; //declare a new Pen object
pen.CreatePen(PS_DASH, 20, RGB(0, 0, 0)); //Create the GDI Pen, dashed, 20 pixels wide, black.
CPen* penOld = dc.SelectObject(&pen); //Tell the DC to use this pen from now on.
dc.Rectangle(rect); //Draw a rectangle (using the current pen)
dc.FillRect(rect, &brush); //Fill a rectangle (using the current brush)
It creates a pen, selects it into the DC, and then instructs the DC to use the pen (which is 20 pixels wide) to draw a rectangle at the specified coordinates. It then fills in the inside of that rectangle with a brush.
in a C++ MFC application. using the dc of ( CPaintDC dc(this); )
How do i draw a rectangle ( LPRECT ) with an alpha transparency that i can adjust.?
Following is an example c# code which i need to convert into C++
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Color color = Color.FromArgb(75,Color.Red); //sets color Red with 75% alpha transparency
Rectangle rectangle = new Rectangle(100,100,400,400);
g.FillRectangle(new SolidBrush(color), rectangle); //draws the rectangle with the color set.
}
You need to look into GDI+. Its a bit of a faff but you can create a "Graphics" object as follows:
Gdiplus::Graphics g( dc.GetSafeHdc() );
Gdiplus::Color color( 192, 255, 0, 0 );
Gdiplus::Rect rectangle( 100, 100, 400, 400 );
Gdiplus::SolidBrush solidBrush( color );
g.FillRectangle( &solidBrush, rectangle );
Don't forget to do
#include <gdiplus.h>
and to call
GdiplusStartup(...);
somewhere :)
You'll notice it's pretty damned similar to your C# code ;)
Its worth noting that the 75 you put in your FromArgb code doesn't set 75% alpha it actually sets 75/255 alpha or ~29% alpha.
GDI (and thus MFC) has no decent support for drawing with an alpha. But GDI+ is available in C++ code as well. Use #include <gdiplus.h> and initialize it with GdiplusStartup(). You can use the Graphics class, create one with its Graphics(HDC) constructor from your CPaintDC. And use its FillRectangle() method. The SDK docs are here.
int StartHoriz,StartVert,BarWidth,BarHeight; // rect start, width and height
StartHoriz=0;
StartVert=100;
width = 100;
height=120;
CDC* pCDC = GetDC(); // Get CDC pointer
CRect Rect(StartHoriz,StartVert,BarWidth,BarHeight); //create rectangle dimensions
pCDC->Rectangle(Rect); //draw rectangle
I have to draw a String on a transparent bitmap at first, then draw A to destination canvas.
However on certain case, there is black border around the characters.
Bitmap* tempImg = new Bitmap(1000, 1000, PixelFormat32bppARGB);
Graphics tempGr(tempImg);
tempGr.Clear(Color(0, 255,255,255));
Gdiplus::SolidBrush* brush = new SolidBrush(Color(255, 255, 0, 0 ));
Gdiplus::FontFamily fontFamily(L"Times New Roman");
Gdiplus::Font* font = new Gdiplus::Font(&fontFamily, 19, FontStyleRegular, UnitPixel);
RectF rec(400, 400, 1000, 10000);
tempGr.DrawString(
L"Merry Chrismas",
-1,
font,
rec,
NULL,
brush
);
Graphics desGr(hdc);
desGr.Clear(Color::Gray);
desGr.DrawImage(tempImg , 0,0, 1000, 1000);
The character draw on desGr have black board for some fontsize.
How can I avoid this problem?
Many thanks!
I think the problem here is that you are drawing the text onto a transparent background.
You could try adding this line after the call to tempGr.Clear...
tempGr.TextRenderingHint = TextRenderingHint.AntiAlias;
ps - sorry not sure the exact syntax in C++ ;)
I just solved this problem in XNA:
Clear background to the same as the foreground color. The only difference is that the background should have Alpha=0, and the foreground with Alpha >> 0
The black border comes from blending of your background and foreground of different colors. Try to clear the background to some contrasting color to fully appreciate the phenomenon.
To get some smooth graphics, I want to draw oversampled by factor 2 and scale down afterwards.
So what I am doing is to draw oversampled on a wxBitmap in a wxMemoryDC, and then scale it down before copying to my dc. The code below works fine, but bitmapOversampled.ConvertToImage(); is extremely slow.
Is there any way to achieve the same without having to convert from wxBitmap to wxImage and vice versa?
void OnPaint
( wxPaintEvent& event )
{
wxBitmap bitmapOversampled(m_width * 2, m_height * 2);
wxMemoryDC memDC(bitmapOversampled);
// Draw the elements.
drawElements(&memDC);
// Scale to correct size.
wxImage image = bitmapOversampled.ConvertToImage();
image.Rescale(m_width, m_height);
memDC.SelectObject(wxBitmap(image));
// Copy to dc.
wxPaintDC dc(this);
dc.Blit(0, 0, m_width, m_height, &memDC, 0, 0);
};
Sadly, there is no portable wx method to do that scaling faster. But there is a Scale method in the Gtk port in wxBitmap. You can use that for wxGTK. For wxMSW, you can use StretchBlt of the win32 API. There are methods in wxDC that will provide you with the native HDC handle for Windows.
You can make it somewhat more straight forward if you draw directly:
wxPaintDC dc(this);
dc.DrawBitmap(image, 0, 0, false);
Also, don't recreate the bitmap in each paint event. Store it as a member, and recreate it only when you get a wxSizeEvent. It will probably considerably speed up your program.
Another way is to drop the scaling altogether and use wxGraphicsContext. It uses Cairo on wxGTK, and gdi+ on wxMSW. It's relatively new, but can draw antialiased.