I am writing a small application that prints some stickers to a special printer.
When I use MS Word to print some text to that printer (and to an XPS file), the result looks excellent. When I print from C# code with the Graphics object, the text appears to be over-pixelized or over-smoothed.
I tried the following hints, but none produced the same result as MS Word:
System.Drawing.Drawing2D.SmoothingMode.AntiAlias
System.Drawing.Text.TextRenderingHint.AntiAliasGridFit
System.Drawing.Text.TextRenderingHint.AntiAlias
System.Drawing.Text.TextRenderingHint.ClearTypeGridFit
InterpolationMode.NearestNeighbor
CompositingQuality.HighQuality
And some others.
Can you advice which hints are applied by MS Word, so I could create it programatically?
I'm not familiar with the Graphics object, but I'm guessing you're sending a bitmap to the printer instead of text or vector graphics.
If so, increase the resolution/DPI of the image you're creating to approach that of the printer, or switch to a rich text (XPS) or vector-based format.
Windows GDI (on which Graphics is based) is a raster technology. You are generating (possibly low-res) bitmaps.
Options include: instantiate a larger graphics object and print bigger text (== increasing resolution of the print), or move to WPF, which has a vector model and lets you generate XPS files natively.
You'll need to be printing at least 300DPI for it to look any good. 600DPI would be better. You're probably printing at something around 96DPI by just drawing straight out to the printer.
Related
i'm using c# tessnet2 wrapper for Tesseract OCR engine to capture chracters of image files. i been searching everywhere if tessnet2 has any build in functions to overwrite certain characters and saved them into the same image file it's reading but have not found anything in regards to that. so what i'm thinking of doing is creating a new imagine file base on what i'm receiving from tessnet2 but i need to create the new image the same exact way but change just few things in the new created image. i'm not sure if i'm using the correct methology or if there is other c# assemblies out there that allow you to read characters from image file and at the same time allow you to manipulate as you need them.
Good luck--but tess has no way of replacing in the proper font. Raster graphics don't generally store glyph information. Even if it did, you would potentially be in violation of licenses and/or copyrights surrounding the fonts you'd be writing in. I'm not an expert in OCR, but I will confidently say that this is something not readily available out there in the wild.
To expand on Brian's answer:
You will need to do this yourself. I have not worked with Tesseract, but I have used the Nuance OCR engine. It will return you font information as well as coordinates for the character it has recognized (note that you will most likely have to compute the actual image coordinate as the OCR engine will have deskewed the image before performing the recognition). Once you get the coordinates and the deskew so that you can compute the actual coordinate, you can then use any image manipulation library (Leadtools, Accusoft, etc) or just straight GDI+ functions to clear the character, then using the font info and size info create a new character and merge it into the image. This is not trivial but certainly doable.
Edit:
It was late when I wrote the initial answer, wanted to clarify what is meant by font information. The OCR engine will give you information regarding the point size, whether its bold/italicized and the font family (Seriph, etc). I do not know of one that will tell you the exact font that the document is in. If you have a sample of the documents that you will process, then you can make a good guess based on the info the OCR engine gives you.
I'm working with a WinForms app. I have an RDLC report that will be printed on 11x17 and then folded (printer supports folding). I'm rendering to EMF and drawing to pages of a PrintDocument. This works fine except for folding.
What I'd like to do is store the settings that make the printer fold. The users would select a preset from a dropdown and the app would select the printer, the paper size, the tray, whether to duplex, and whether to fold. Storing the PrinterSettings object covers most of this, but doesn't save the folding option.
I first attempted to store/retrieve something I read about called DEVMODE. For reference: http://nicholas.piasecki.name/blog/2008/11/programmatically-selecting-complex-printer-options-in-c-shar/. What I found is that even though I had extra data specific to the driver, all the bytes were 0 regardless of what driver-specific settings I changed. I'm not sure where I went wrong with this, but I abandoned it and looked at the printing capabilities in WPF.
I found that I could configure a PrintTicket for my settings, store it, and retrieve it later. It seems a bit convoluted just to save the settings, but I think I have it working. At least it seems to show up correctly in the PrintDialog. However, I'm now stuck trying to figure out how to print my report.
As I understand it, I can't take a PrintDocument from WinForms printing and use it in WPF. I also read EMF format is not supported in WPF. I thought I would render each EMF to a bitmap, then print those. But the text in my report is fuzzy and I'm not having any luck clearing it up.
Starting with a stream that contains EMF bytes that I know will render sharply with PrintDocument, I test trying to save to a file. It seems no settings that I provide will save with crisp text.
var pageImage = new Metafile(stream);
pageImage.Save(filename);
All this just to add the ability to fold. Am I just completely on the wrong track? I don't see how this should be so hard. I guess I either need to find another way to save/restore custom printer settings or I need a way to render these EMF files better.
I also tried rendering the report directly to BMP format and it's also poor quality.
I tried something slightly different and it worked! I reused my original PrintDocument code and printed to an XPS file. Then I printed the XPS file using my PrintTicket and it works fine.
Is this possible or do I have to use WPF. I am new to Winforms and have created a couple simple applications, now I need to read a TIFF file and then display a subsection of it...
I tried doing something like this:
Graphics g = e.Graphics;
Bitmap b = new Bitmap(Image.FromFile(#"W:\ILHSR_Merged_2011\compressed\overviews\ILHSR11_0405-101-1.tif"));
g.DrawImage(b, 10, 10, 350, 300);
But I get out of memory exceptions. Can someone point me to some readin, or is this simply something that should be developed in WPF.
I think you need to implement you own TIFF loader using libTiff.
TIFF image format allow to store image data in tiles. LibTiff allows you to load single tiles: in this way you can display only portion of the image (without decoding the entire TIFF!, that can have prohibitive sizes).
Unfortunately, I don't think that .NET imaging supports that TIFF feature. My suggestion is to wrap libTiff in a library written in C++/CLI, and integrate it in your application.
(Due comment: if some existing library has already wrapped libTiff, and its interface match nicely with your application, even the better)
If you need to display parts, consider using tiled Tif files, and possibly even image pyramids (see TIF pyramid for background info on how to create/use them) tif files. All of these can be read with LibTiff and LibTiff.NET
Of course this depends on how often you need to do it. My experience is that very large bitmaps cannot be displayed properly using 32bit windows versions, unless the file itself is tiled. I have made a wrapper for LibTiff.NET, which allows Tile access also for non tiled (uncompressed, or line based) files. Of course, access is slower then; you'd need to read the entire rows which are on display. Still response time was reasonable for gigapixel images.
BitMiracle LibTiff.NET mentioned in previous post/comment works great: see How to implement pan/zoom on gigapixel bitmaps? and How to implement pan/zoom on gigapixel bitmaps?; it is a native c# implementation of LibTiff, which I found easier to handle than a wrapper class (because there is no unmanaged memory blocks to take care of in c# app).
[Edit]Added link to TIF pyramid image documentation[/Edit]
Currently i use Ghostscript to convert color PDF's to grayscale PDF's. Now i'm looking for reliable .NET commercial or not commercial component/library for ghostscript replacement. I googled and I did not find any component/library that is able to do that easily or to do that at all.
EDIT #1:
Why Ghostscript does not work for me:
I implemented Ghostscript and I'm using it's native API's. The problem is that Ghostscript does not support multiple instances of the interpreter within a single process. -dJOBSERVER mode also does not work for me because i don't collect all job and them process them all at once. It happens that Ghostscript is processing large job which takes around 20 minutes and meanwhile i get some smaller job which has to be processed ASAP and cannot wait 20 minutes. Other problem is that Ghostscript page processed events are not easily to catch. I wrote a parser for ghostscript stdout messages and i can read out processed page number but not for each page when it's processed as ghostscript pushes message for group of processed pages. There are couple of more problems with Ghostscript like producing bad pdf's, duplicating font problems.....
You can find one more problem i had with ghostscript here: Ghostscript - PS to PDF - Inverted images problem
-
a year after UPDATE:
Before a year a go i asked this question. Later i made my own solution by using iTextSharp.
You can take a look at the converting PDF to grayscale solution here:
http://habjan.blogspot.com/2013/09/proof-of-concept-converting-pdf-files.html
or
https://itextsharpextended.codeplex.com/
Works for me in most cases :)
Not quite an answer, but I think you dismiss Ghostscript too quickly.
Are you aware of the GhostScript API (for in-process Ghostscript)? Or of the -dJOBSERVER mode that can take a series of PS commands piped to its standard in?
That still won't get you your callbacks however, and it's still not multi-threaded.
As previously stated, iText could do it, but it would be a matter of walking through all the content and images looking for non-grayscale color spaces and converting them in a space-specific manner.
You'd also have to replace the pixel data in any images you might find.
The good news is that iText[Sharp] is capable of operating in multiple threads, provided each document is used from one thread at a time.
I suspect this is also the case for the suggested commercial library, which isn't such a good deal.
And then a light went on above my head... drawn in gray scale.
Blending modes and transparency groups!
Take all the current page content and stick it in a transparency group that is blended with a solid black rectangle that covers the page. I think there's even a luminosity to alpha blend mode... lets see here.
Yep, PDF reference section 11.6.5.2 "Soft Mask Dictionaries". You'll want a "luminosity" group.
Now, the bad news. If your goal in switching to gray scale is to save space, this will fail utterly. It'll actually make each file a little larger... say a 100 bytes per page, give or take.
The software rendering the PDF better be pretty hot stuff too. Your cousin's undergrad rendering project need not apply. This is advanced graphics stuff here, infrequently used by Common PDF Files, so the last sort of thing to be implemented.
So... For each original page
Create a new page.
Cover it with a black background.
Cover it with a white rectangle (had it backwards earlier) in a transparency group that uses a soft mask dictionary set to be the luminosity of the original page's content (now stashed in an XObject Form).
Because this is all your own code, you'll have ample opportunity to do whatever it is you want to do at the beginning or end of each page.
By golly, that's just crazy enough to work! It does require some PDF-Fu, but not nearly as much as the "convert each color space and image in various ways as I step through the document". Deeper knowledge, less code to write.
This isn't a .net library, but rather a potential work-around. You could install a virtual printer that is capable of writing PDF files. I would suggest CutePDF, as it's free, easy to use and does a great job 'printing' a large number of file formats to PDF. You can do nearly everything with CutePDF that you can do with a normal printer, including printing to grayscale.
After the virtual printer is installed, you can use c# to 'print' a greyscale version.
Edit: I just remembered that the free version is not silent. Once you print to the CutePDF printer, it will ask you to 'Save As'. They do have an SDK available for purchase, but I couldn't say whether it would be able to help you convert to grayscale.
If a commercial product is a valid option for you, allow me to recommend Amyuni PDF Creator .Net. By using it you will be able to enumerate all items inside the page and change their colors accordingly, images can also be set as grayscale. Usual disclaimers apply
Sample code using Amyuni PDF Creator ActiveX, the .Net version would be similar:
pdfdoc.ReportState = ReportStateConstants.acReportStateDesign;
object[] page_items = (object[])pdfdoc.get_ObjectAttribute("Pages[1]", "Objects");
string[] color_attributes = new string[] { "TextColor", "BackColor", "BorderColor", "StrokeColor" };
foreach (acObject page_item in page_items)
{
object _type = page_item["ObjectType"];
if ((ACPDFCREACTIVEX.ObjectTypeConstants)_type == ACPDFCREACTIVEX.ObjectTypeConstants.acObjectTypePicture)
{
page_item["GrayScale"] = true;
}
else
foreach (string attr_name in color_attributes)
{
try
{
Color color = System.Drawing.ColorTranslator.FromWin32((int)page_item[attr_name]);
int grayColor = (int)(0.3 * color.R + 0.59 * color.G + 0.11 * color.B);
int newColorRef = System.Drawing.ColorTranslator.ToWin32(Color.FromArgb(grayColor, grayColor, grayColor));
page_item[attr_name] = newColorRef;
}
catch { } //not all items have all kinds of color attributes
}
}
Before a year a go i asked this question. Later i made my own solution by using iTextSharp.
You can take a look at the converting PDF to grayscale solution here: https://itextsharpextended.codeplex.com/
iTextPdf a good product for creating/managing pdf it has got both commercial and free versions.
Have a look at aspose.pdf for .net it provides below features and a lot more.
Add and remove watermarks from PDF document
Set page margin, size, orientation, transition type, zoom factor and appearance of PDF document
..
And here is a list of open source pdf libraries.
After a lot of investigation i found out about ABCpdf from Websupergoo. Their component can easily convert any PDF page to grayscale by simple call to Recolor method. The component is commercial.
Is there a way to draw an emf metafile (exported form a drawing tool) with antialiasing enabled? The tools I tried are not capable of exporting emf files antaliased so I wondered if I can turn it back on manually when drawing the emf in the OnPaint override of my Controls.
If anyone can confirm that is technically possible to generate antialiased emf files, another solution would be to use a drawing tool that can export to antialiased emf or have a 3rd party converter do this later. If anyone knowns such a tool, please let me know.
EDIT: When looking at the emf instructions it doesn't seem that emf itself can actually store the information whether it is to be rendered antialiased or not. At least I couldn't find anything. It is more likely that the antialiasing is done by the playback engine. For example when I open an emf in Word 2007 it is rendered antialiased. But not when I draw it with GDI+ "playback engine" (Graphics.DrawImage(...)). or when I view it the standard windows image viewer.
This makes me believe that some tools actually have their own emf playback engine. So maybe there is free .NET library (preferably with source code) that give me an object model of the emf instructions stored in the parsed emf file so I can play it back myself instead of using Graphics.DrawImage(...)?
We had a similar issue in a DirectX project. Upscaling and downscaling works to a certain degree, but it's faking it. If it's something you need to do over and over, you could perhaps parse the records of the WMF and draw them with GDI+ antialiased.
The following threads back this up (but they're from 2005 so things might have changed):
http://www.dotnet247.com/247reference/msgs/28/144605.aspx
http://www.dotnetmonster.com/Uwe/Forum.aspx/dotnet-sdk/1127/Graphics-DrawImage-metafile-no-antialiasing
[Edit:]
These three programs might do the job for you: I'm assuming you're ok with doing it by hand:
http://emf-to-vector-converter-command-line-ser.smartcode.com/info.html
http://www.verypdf.com/pdf-editor/index.html
http://www.ivanview.com/converter/emf-batch-converter.html
[Edit II:]
Well, here's a program that will let you inspect an EMF in various ways:
http://download.cnet.com/windows/3055-2383_4-10558240.html?tag=pdl-redir
...and here's a freeware library that will let you parse 122 of the EMF commands and output them in GDI+. That should probably do the trick:
http://www.codeproject.com/KB/GDI-plus/emfexplorer.aspx?msg=2359423
...oh, and notice also comment #3 on the codeproject page. Looks like someone have banged their heads against the wall before. Hope this solves your problem.
EMF is using GDI commands, not GDI+, so it has no notion of antialiasing. I suspect that when you ask GDI+ to render the file, it sends it to GDI and just copies the resulting bitmap.
Duplicating this in code would be the same as reimplementing GDI, so it's not terribly feasible. Not impossible, just a larger job than the benefit would justify. If there is an open source utility that can open EMF files outside of Windows, you might look into the source code.
My guess is that Word is using the downsampling trick.
EMF file is a list of GDI commands. So it won't be anti-aliaised, even if under GDI+, you put a SmoothingMode() call before the drawing. You'll have to enumerate the GDI commands, then translate it into GDI+ commands.
Under Vista/Seven, you can use GDI+ 1.1 function named GdipConvertToEmfPlus/ConvertToEmfPlus. If you want your program to work with XP, you should write your own enumeration, then conversion to GDI+ commands.
The GDI enumeration then conversion to GDI+ is possible has been done by emfexplorer, but I've written some code perhaps more easy to follow, even if it's written in Delphi.
I'm putting this answer just now (I'm late), because I spent a lot of time finding out a solution using ConvertToEmfPlus, and writing some tuned open source code in case this method is not available.