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: using <code>system.drawing.graphics</code>

using gdi32.dll: using <code>gdi32.dll</code>

update

after testing of code...i got strange stuff.

enter image description here

this way draw multiple independent stroke of semi-transparent color without piling alpha:

enter image description here

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:

enter image description here

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:

enter image description here


Comments

Popular posts from this blog

ZeroMQ on Windows, with Qt Creator -

unity3d - Unity SceneManager.LoadScene quits application -

python - Error while using APScheduler: 'NoneType' object has no attribute 'now' -