gdi - c# Drawing with gdi32.dll vs System.Drawing.Graphics -
so have code creates highlight effect on top of picture box gdi32.dll , wondering if there simpler way system.drawing.graphics
? gdi32.dll, have capture screen shot after drawing, post picturebox , able draw more stuff , change color of pen use. if try change pen thickness , color , draw on screen again, if changes drew.
now have version of uses system.drawing.graphics
, lots of math fillpolygon
if draw on area drew on, makes area drew on darker. not gdi32.dll justr shades long have not shaded area mouse. suggestions?
public partial class form9 : form { private bool is_mouse_down { get; set; } // check if mouse down or not. private color pen_color = new color(); private int pen_type { get; set; } private int thickness { get; set; } private bool start { get; set; } list<point> points = new list<point>(); public form9() { initializecomponent(); picturebox1.dock = dockstyle.fill; pen_color = color.blue; pen_type = 13; // type = 9 highlighter, type = 13 solid. thickness = 2; start = false; picturebox1.mousedown += picturebox1_mousedown; picturebox1.mouseup += picturebox1_mouseup; picturebox1.mousemove += picturebox1_mousemove; picturebox1.paint += picturebox1_onpaint; } private void drawhighlight(graphics g, point[] usepoints, int brushsize, int pentype, color brushcolor) { int usecolor = system.drawing.colortranslator.towin32(brushcolor); intptr pen = getimage.gdi32.createpen(getimage.gdi32.ps_solid, brushsize, (uint)usecolor); intptr hdc = g.gethdc(); intptr xdc = getimage.gdi32.selectobject(hdc, pen); getimage.gdi32.setrop2(hdc, pentype);//getimage.gdi32.r2_maskpen); (int = 1; <= usepoints.length - 1; i++) { point p1 = usepoints[i - 1]; point p2 = usepoints[i]; getimage.gdi32.movetoex(hdc, p1.x, p1.y, intptr.zero); getimage.gdi32.lineto(hdc, p2.x, p2.y); } getimage.gdi32.setrop2(hdc, getimage.gdi32.r2_copypen); getimage.gdi32.selectobject(hdc, xdc); getimage.gdi32.deleteobject(pen); g.releasehdc(hdc); } private void picturebox1_onpaint(object sender, painteventargs e) { if (start) { base.onpaint(e); if (is_mouse_down) { drawhighlight(e.graphics, points.toarray(), thickness, pen_type, pen_color); } } } private void picturebox1_mousedown(object sender, mouseeventargs e) { points.clear(); start = true; is_mouse_down = true; } private void picturebox1_mouseup(object sender, mouseeventargs e) { is_mouse_down = false; using (image img = capturescreen()) { try { if (system.io.file.exists(program.programpath + @"\temp\marked.bmp")) { system.io.file.delete(program.programpath + @"\temp\marked.bmp"); } } catch (exception ex) { messagebox.show("file delete error" + environment.newline + convert.tostring(ex)); } try { img.save(program.programpath + @"\temp\marked.bmp", system.drawing.imaging.imageformat.bmp); } catch (exception ex) { messagebox.show("unable save screenshot" + environment.newline + convert.tostring(ex)); } } if (system.io.file.exists(program.programpath + @"\temp\marked.bmp")) { using (filestream fs = new system.io.filestream(program.programpath + @"\temp\marked.bmp", system.io.filemode.open, system.io.fileaccess.read, fileshare.read)) { picturebox1.image = image.fromstream(fs); } } picturebox1.invalidate(); // refreshes picturebox image. } public image capturescreen() { getimage gi = new getimage(); return gi.capturewindow(getimage.user32.getdesktopwindow()); } private void picturebox1_mousemove(object sender, mouseeventargs e) { if (is_mouse_down == true) // check see if mouse button down while moving on form. { points.add(new point(e.x, e.y)); picturebox1.invalidate(); // refreshes picturebox image. } }
here couple photos of talking about:
using system.drawing.graphics
:
update
after testing of code...i got strange stuff.
this way draw multiple independent stroke of semi-transparent color without piling alpha:
it uses tow lists, 1 strokes , 1 current stroke:
list<list<point>> strokes = new list<list<point>>(); list<point> currentstroke = new list<point>();
they filled in usual way
private void canvas_mousedown(object sender, mouseeventargs e) { if (e.button.hasflag(mousebuttons.left)) { currentstroke.add(e.location); if (currentstroke.count == 1) currentstroke.add(new point(currentstroke[0].x + 1, currentstroke[0].y)); canvasinvalidate(); } } private void canvas_mousemove(object sender, mouseeventargs e) { if (e.button.hasflag(mousebuttons.left)) { currentstroke.add(e.location); canvas.invalidate(); } } private void canvas_mouseup(object sender, mouseeventargs e) { if (currentstroke.count > 1) { strokes.add(currentstroke.tolist()); currentstroke.clear(); } canvas.invalidate(); }
in version avoid overlay effects of overlapping strokes drawing pixels in 1 call. pixels painted creating graphicspath
strokes , and filling it:
private void canvas_paint(object sender, painteventargs e) { if (strokes.count > 0 || currentstroke.count > 0) { graphicspath gp = new graphicspath(); gp.fillmode = fillmode.winding; if (currentstroke.count > 0) { gp.addcurve(currentstroke.toarray()); gp.closefigure(); } foreach (var stroke in strokes) { gp.addcurve(stroke.toarray()); gp.closefigure(); } using (solidbrush b = new solidbrush(color.fromargb(77, 177, 99, 22))) { e.graphics.fillpath(b, gp); } } }
note should take care not move onto current stroke while drawing or else croosing path parts create holes!
a clear
or save
button
simple, former clears
2 list , invalidates, latter use drawtobitmap
save control..
note: avoid flicker make sure canval panel doublebuffered
!
update:
here way uses pen
draw overlay. avoid piling of alpha , changed color values (depending on pixelformat
) uses fast function modify set pixels in overlay have same overlay color:
the stroke collection code same. paint
reduced calling function create overlay bitmap , drawing it:
private void canvas_paint(object sender, painteventargs e) { using (bitmap bmp = new bitmap(canvas.clientsize.width, canvas.clientsize.height, pixelformat.format32bpppargb)) { painttobitmap(bmp); e.graphics.drawimage(bmp, 0, 0); }
the first function drawing, pretty before, simple pen strokes:
private void painttobitmap(bitmap bmp) { color overlaycolor = color.fromargb(77, 22, 99, 99); using (graphics g = graphics.fromimage(bmp)) using (pen p = new pen(overlaycolor, 15f)) { p.miterlimit = p.width / 2; p.endcap = linecap.round; p.startcap = linecap.round; p.linejoin = linejoin.round; g.smoothingmode = smoothingmode.antialias; if (currentstroke.count > 0) { g.drawcurve(p, currentstroke.toarray()); } foreach (var stroke in strokes) g.drawcurve(p, stroke.toarray()); } setalphaoverlay(bmp, overlaycolor); }
it calls function 'flattens' set pixels overlay color:
void setalphaoverlay(bitmap bmp, color col) { size s = bmp.size; pixelformat fmt = bmp.pixelformat; rectangle rect = new rectangle(point.empty, s); bitmapdata bmpdata = bmp.lockbits(rect, imagelockmode.readonly, fmt); int size1 = bmpdata.stride * bmpdata.height; byte[] data = new byte[size1]; system.runtime.interopservices.marshal.copy(bmpdata.scan0, data, 0, size1); (int y = 0; y < s.height; y++) { (int x = 0; x < s.width; x++) { int index = y * bmpdata.stride + x * 4; if (data[index + 0] + data[index + 1] + data[index + 2] > 0) { data[index + 0] = col.b; data[index + 1] = col.g; data[index + 2] = col.r; data[index + 3] = col.a; } } } system.runtime.interopservices.marshal.copy(data, 0, bmpdata.scan0, data.length); bmp.unlockbits(bmpdata); }
it uses lockbits
, pretty fast..
here in action:
update 2:
just fun of here extension of few lines adds option of drawing filled curves:
the fill mode stored in cheapo hack having 1st element twice. these changes:
in mousedown
:
currentstroke.add(e.location); if (cbx_fill.checked) currentstroke.add(e.location);
and in painttobitmap
:
g.smoothingmode = smoothingmode.antialias; if (currentstroke.count > 0) { if (cbx_fill.checked) g.fillclosedcurve(b, currentstroke.toarray()); else g.drawcurve(p, currentstroke.toarray()); } foreach (var stroke in strokes) if (stroke[0]==stroke[1]) g.fillclosedcurve(b, stroke.toarray()); else g.drawcurve(p, stroke.toarray());
and 1 more demo:
Comments
Post a Comment