richtextbox - how to save drew Graphics of "Paint()" into image using c#? -
(sorry if post duplicate or ...)
i wanted convert rtf image after googling lot i've got code paint() event of picturebox1 , works :
private void picturebox1_paint(object sender, painteventargs e) { e.graphics.clear(richtextbox1.backcolor); e.graphics.drawrtftext(this.richtextbox1.rtf, this.picturebox1.clientrectangle); base.onpaint(e); // below code create empty image file bitmap newbitmap = new bitmap(picturebox1.width, picturebox1.height); e.graphics.drawimage(newbitmap, new rectangle(0, 0, picturebox1.width, picturebox1.height), new rectangle(0, 0, picturebox1.width, picturebox1.height), graphicsunit.pixel); newbitmap.save(@"c:\adv.jpg"); }
in picture above left richtextbox , right picturebox.
the issue don't know how save paint() drew graphic file.because 3 last lines of code save empty image.
any appreciated?
update #1:
g.smoothingmode = smoothingmode.antialias; g.textrenderinghint = system.drawing.text.textrenderinghint.cleartypegridfit; g.interpolationmode = interpolationmode.highqualitybicubic; g.pixeloffsetmode = pixeloffsetmode.highquality; g.clear(richtextbox1.backcolor); g.drawrtftext(this.richtextbox1.rtf, this.picturebox1.clientrectangle);
by changing graphics e.graphics g issue resolved 1 other issue quality of bitmap low. i've added bunch of code i've got same result, quality low! suggestions?
update #2
here graphics_drawrtftext class conversion :
public static class graphics_drawrtftext { private static richtextboxdrawer rtfdrawer; public static void drawrtftext(this graphics graphics, string rtf, rectangle layoutarea) { if (graphics_drawrtftext.rtfdrawer == null) { graphics_drawrtftext.rtfdrawer = new richtextboxdrawer(); } graphics_drawrtftext.rtfdrawer.rtf = rtf; graphics_drawrtftext.rtfdrawer.draw(graphics, layoutarea); } private class richtextboxdrawer : richtextbox { //code converted code found here: http://support.microsoft.com/kb/812425/en-us //convert unit used .net framework (1/100 inch) //and unit used win32 api calls (twips 1/1440 inch) private const double aninch = 14.4; protected override createparams createparams { { createparams createparams = base.createparams; if (safenativemethods.loadlibrary("msftedit.dll") != intptr.zero) { createparams.exstyle |= safenativemethods.ws_ex_transparent; // transparent createparams.classname = "richedit50w"; } return createparams; } } public void draw(graphics graphics, rectangle layoutarea) { //calculate area render. safenativemethods.rect rectlayoutarea; rectlayoutarea.top = (int)(layoutarea.top * aninch); rectlayoutarea.bottom = (int)(layoutarea.bottom * aninch); rectlayoutarea.left = (int)(layoutarea.left * aninch); rectlayoutarea.right = (int)(layoutarea.right * aninch); intptr hdc = graphics.gethdc(); safenativemethods.formatrange fmtrange; fmtrange.chrg.cpmax = -1; //indicate character character fmtrange.chrg.cpmin = 0; fmtrange.hdc = hdc; //use same dc measuring , rendering fmtrange.hdctarget = hdc; //point @ printer hdc fmtrange.rc = rectlayoutarea; //indicate area on page print fmtrange.rcpage = rectlayoutarea; //indicate size of page intptr wparam = intptr.zero; wparam = new intptr(1); //get pointer formatrange structure in memory intptr lparam = intptr.zero; lparam = marshal.alloccotaskmem(marshal.sizeof(fmtrange)); marshal.structuretoptr(fmtrange, lparam, false); safenativemethods.sendmessage(this.handle, safenativemethods.em_formatrange, wparam, lparam); //free block of memory allocated marshal.freecotaskmem(lparam); //release device context handle obtained previous call graphics.releasehdc(hdc); } #region safenativemethods private static class safenativemethods { [dllimport("user32.dll")] public static extern intptr sendmessage(intptr hwnd, int msg, intptr wp, intptr lp); [dllimport("kernel32.dll", charset = charset.auto)] public static extern intptr loadlibrary(string lpfilename); [structlayout(layoutkind.sequential)] public struct rect { public int left; public int top; public int right; public int bottom; } [structlayout(layoutkind.sequential)] public struct charrange { public int cpmin; //first character of range (0 start of doc) public int cpmax; //last character of range (-1 end of doc) } [structlayout(layoutkind.sequential)] public struct formatrange { public intptr hdc; //actual dc draw on public intptr hdctarget; //target dc determining text formatting public rect rc; //region of dc draw (in twips) public rect rcpage; //region of whole dc (page size) (in twips) public charrange chrg; //range of text draw (see earlier declaration) } public const int wm_user = 0x0400; public const int em_formatrange = wm_user + 57; public const int ws_ex_transparent = 0x20; } #endregion } }
disclaimer: don't have time dig posted extension method interesting , works well, @ least when drawing onto control surface.
but reproduce how bad results when drawing bitmap..
but: when done right saved results excellent!
so here here few things keep in mind:
saving in
paint
event bad idea, event triggered system whenever needs redraw control; test doing minimize/maximize cycle.in addition
drawrtftext
semms create double-vision effect when drawing bitmap.so make sure use
drawtobitmap
grab results. need place calldrawrtftext
inpaint
event of control!also make sure have large enough resolutions both in control (pixel size) , bitmap (dpi) nice, crispy , (if needed) printable results.
do not save
jpg
bound result in blurry text!png
format of choice!
here paint
event:
private void panel1_paint(object sender, painteventargs e) { e.graphics.clear(richtextbox1.backcolor); e.graphics.textrenderinghint = system.drawing.text.textrenderinghint.antialias; e.graphics.smoothingmode = smoothingmode.antialias; padding pad = new padding(120, 230, 10, 30); // pick own numbers! size sz = panel1.clientsize; rectangle rect = new rectangle(pad.left, pad.top, sz.width - pad.horizontal, sz.height - pad.vertical); e.graphics.drawrtftext(this.richtextbox1.rtf, rect); }
note pays improve on default quality settings; if don't text in resulting file break apart when zooming in..
here save button click:
private void button1_click(object sender, eventargs e) { size sz = panel1.clientsize; // first (optionally) create bitmap in original panel size: rectangle rect1 = panel1.clientrectangle; bitmap bmp = new bitmap(rect1.width, rect1.height); panel1.drawtobitmap(bmp, rect); bmp.save("d:\\rtfimage1.png", imageformat.png); // create 4x larger one: rectangle rect2 = new rectangle(0, 0, sz.width * 4, sz.height * 4); bitmap bmp2 = new bitmap(rect2.width, rect2.height); // need temporarily enlarge panel: panel1.clientsize = rect2.size; // can let routine draw panel1.drawtobitmap(bmp2, rect2); // , before saving optionally can set dpi resolution bmp2.setresolution(300, 300); // optionally make background transparent: bmp2.maketransparent(richtextbox1.backcolor); unsemi(bmp2); // see link in comment! // save text png; jpg fotos! bmp2.save("d:\\rtfimage2.png", imageformat.png); // restore panels size panel1.clientsize = sz; }
i found result good.
note drawtobitmap
internally trigger paint
event grab drawn graphics.
of course don't need both parts - use 1 want (.e. skip 1st part, between first
, now
) , use own numbers. helps know output shall , calculate necessary sizes , resolutions backward there.
i added enlarged version because monitor resolution, controls have, rather limited, around 75-100dpi, while print quality starts @ 150dpi..
here link unsemi function
Comments
Post a Comment