How to set exact length of Crystal report through code? - c#

I have a report designed in Crystal Rerports 12x8.5 inch. I have my OKI 3320 printer driver set exactly to this size.
Now, when I print the report using my C# code, the page length is half inch short of the tear off position. I have to roll up paper to tear it off. Is there any settings we can change through code to exactly get to the tear off position?
ReportDocument oReportDocument = new ReportDocument();
oReportDocument.Load(reportPath + "\\OutDkt.rpt");
List<TblOutDocket> lstDockets = new List<TblOutDocket>();
lstDockets.Add(oTblOutDocket);
oReportDocument.SetDataSource(lstDockets);
oReportDocument.PrintOptions.PrinterName = LocalPrintServer.GetDefaultPrintQueue().FullName;
oReportDocument.PrintToPrinter(1, false, 0, 0);

It seems when you are using custom page sizes you need to specify the page settings specifically. According to this link you can achieve this by setting the PageSettings namespace.
When you want to use a papersize with an id greater then 118 (Windows
coded papersize) you must supply the id of your papersize to
PrintOptions.PaperSource. Obviuosly you need to cast it at
CrystalDecisions.Shared.PaperSource I do this:
ReportDocument.PrintOptions.PaperSource =
(CrystalDecisions.Shared.PaperSource)m_PageSettings.PaperSource.RawKind;
ReportDocument.PrintOptions.PaperSize =
(CrystalDecisions.Shared.PaperSize)m_PageSettings.PaperSize.RawKind;
Where m_PageSettings is my System.Drawing.PageSettings that specify
the right PaperSize

Related

NTwain ICapSupportedSizes is Not Supported

I'm using NTwain to scan documents into memory and I have it all working except for one part: When trying to set the size of the page to scan, it scans the entire width and height, rather than just the specified size.
I went and examined the details of NTwain's capabilities on the current source, and found the the ICapSupportedSizes was not supported for any action.
Here's how I'm setting the capabilities (this is on an open, valid source)
_twain.CurrentSource.Capabilities.ICapXResolution.SetValue(new TWFix32() { Whole = 600 });
_twain.CurrentSource.Capabilities.ICapYResolution.SetValue(new TWFix32() { Whole = 600 });
_twain.CurrentSource.Capabilities.ICapPixelType.SetValue(PixelType.BlackWhite);
_twain.CurrentSource.Capabilities.ICapSupportedSizes.SetValue(SupportedSize.USLegal);
_twain.CurrentSource.Capabilities.CapDuplexEnabled.SetValue(BoolType.False);
UPDATE:
I've found out that none of the settings are actually working. I set it as black and white, even if it shows black and white in the settings, it displays in color. Doesn't matter what DPI I set it at either as it defaults to 300 no matter what. I've updated it to grab out the source and use that to change the settings and call Enable, but it still doesn't work.
Any help is appreciated.
Thanks!
Enviornment Information
.NET Framework 4.6.1
Win Forms
C#
NTwain
Scanner: Canon Flatbed Scanner Unit 102
You will need to use the DGImage.ImageLayout property to set the page size in a generally-supported way.
For example:
var ds = _twain.CurrentSource;
ds.Capabilities.ICapUnits.SetValue(Unit.Inches);
ds.DGImage.ImageLayout.Get(out TWImageLayout imageLayout);
imageLayout.Frame = new TWFrame
{
Left = 0,
Right = pageWidthInInches,
Top = 0,
Bottom = pageHeightInInches
};
ds.DGImage.ImageLayout.Set(imageLayout);

Page Width does not match Paper Size in Windows Print Dialog

I am trying to print to an unusual printer (BIXOLON SPP-R200III) from a C# WPF application. The width of this printer's paper roll is 58mm, as measured with a ruler and as shown in the Windows Print Dialog box:
However, when I try to connect to this printer and interrogate its capabilities via the System.Printing APIs in the .NET Framework, I get a different paper width.
The following code enumerates print queues and finds the correct one:
const string printQueueName = #"BIXOLON SPP-R200III";
PrintServer printServer = new PrintServer();
PrintQueue printQueue = null;
PrintQueueCollection printQueues = printServer.GetPrintQueues();
foreach (PrintQueue queue in printQueues)
{
if (String.Equals(queue.FullName, printQueueName, StringComparison.CurrentCultureIgnoreCase))
{
printQueue = queue;
break;
}
}
This code interrogates its capabilities:
PrintTicket defaultTicket = printQueue.DefaultPrintTicket;
PrintCapabilities printCapabilities = printQueue.GetPrintCapabilities(defaultTicket);
double pageWidth = (printCapabilities.OrientedPageMediaWidth.Value / 96.0) * 25.4;
But the result, pageWidth is 48.047 and not 58mm as expected!(PrintCapabilities.OrientedPageMediaWidth is 181.59496062992128.)
I also tried looking at the default print-ticket structure itself but printQueue.DefaultPrintTicket.PageMediaSize.Width has the same value of 181.59496062992128.
Finally, I tried to use the System.Windows.Controls.PrintDialog with the following code:
PrintDialog printDialog = new PrintDialog();
printDialog.PrintQueue = printQueue;
printDialog.ShowDialog();
double pageWidth = (printDialog.PrintTicket.PageMediaSize.Width.Value / 96.0) * 25.4;
And I got the same result.
Why is this? Why do these widths not match? Am I converting from dots to millimetres incorrectly? Am I completely misunderstanding printer capabilities?
What is the right way to find the paper size supported by a printer, like it is shown in the screenshot at the top of this question?
Because there is so called "imageble area", which is always smaller than the physical dimensions of the sheet.
Probably, your printer cannot print at the very edge of the sheet.
You can make sure by inspecting the PrintCapabilities.PageBorderlessCapability Property.
See this link: https://msdn.microsoft.com/en-us/library/system.printing.printcapabilities.pageborderlesscapability(v=vs.110).aspx
Most laser and inkjet printers do not support borderless printing. They must allow an unprinted margin to prevent toner from getting on the parts of the printer that move the paper. Many photographic printers, however, do support borderless printing.
If the printer does not support borderless printing, the collection is empty.

Printing WPF controls without using PrintDialog isn't fully rendering on sizes larger than NorthAmericanLetter sized paper

I have run into a problem that seems to have little information on the web and has been giving me trouble the past two days. When I print to an 8.5 x 11" piece of paper, the output is correct on all printers. When I print to 11 x 17", the output is correct on all virtual (doPDF7, XPS Document Writer) printers. The output on an actual physical printer (Xerox WorkCentre 7535) only renders, from the top-left corner, 8.5 x 11" worth of my control onto a 11 x 17" piece of paper. My control is properly sized (dimension of the 11 x 17") it just doesn't get completely rendered.
I have a Print Preview control implemented where the user can select a printer (PrintQueue) and the settings (PrintCapabilities) for their selected printer. Changing these settings will show up during run time so the user knows exactly what they are printing.
When the user then wants to print their document, I prepare the selected PrintQueue by merging the ticket (their selections in the print preview) with the PrintQueue.CurrentJobSettings.CurrentPrintTicket:
public void Prepare(PrintTicket ticketToMerge)
{
// _printer is the PrintQueue
// I've also tried to merge with UserPrintTicket, DefaultPrintTicket, and created a PrintTicket using XPS Document Writer printer default print ticket
System.Printing.ValidationResult result = _printer.MergeAndValidatePrintTicket(_printer.CurrentJobSettings.CurrentPrintTicket, ticketToMerge);
_printer.CurrentJobSettings.CurrentPrintTicket = result.ValidatedPrintTicket;
_printer.Commit();
// _printer.Refresh(); // This doesn't help it seems
}
then I call to print my DocumentPaginator:
public void Print(DocumentPaginator paginator)
{
var writer = PrintQueue.CreateXpsDocumentWriter(_printer);
writer.Write(paginator, _printer.CurrentJobSettings.CurrentPrintTicket);
}
and the actual printer calls DocumentPaginator.GetPage:
public override DocumentPage GetPage(int pageNumber)
{
var view = new PrintingContent
{
// Create my control and make it the biggest size it can be without
// going into the margins
// Subtract the margins since they can't be printed in, these come from
// _printerCapabilities.PageImageableArea
Width = this.PageSize.Width - this.Margin.Left - this.Margin.Right,
Height = this.PageSize.Height - this.Margin.Top - this.Margin.Bottom,
// This might be a problem since the print preview control
// is also using "this" but haven't found any evidence to conclude this thought
DataContext = this
};
view.Measure(new Size(view.Width, view.Height));
view.Arrange(new Rect(new Point(), new Size(view.Width, view.Height)));
view.UpdateLayout();
var dg = UItilities.FindVisualChildren<DataGrid>(view).First();
// dg.ItemsSource = (File as ParameterCollectionShell).GetParametersByPage(pageNumber)
// This didn't work so I tried giving the datagrid a new instance of List - this might be causing problems?
var parameters = new List<ParameterViewModel>((File as ParameterCollectionShell).GetParametersByPage(pageNumber));
dg.ItemsSource = parameters;
// Doesn't seem to help
// view.Measure(new Size(view.Width, view.Height));
// view.Arrange(new Rect(new Point(), new Size(view.Width, view.Height)));
view.UpdateLayout();
//return new DocumentPage(view,
// this.PageSize,
// new Rect(new Point(), new Size(view.Width, view.Height)),
// new Rect(new Point(this.Margin.Left, this.Margin.Top),
// new Size(view.Width, view.Height)));
return new DocumentPage(view);
}
Of course I have debugged this and checked sizes to make sure they are what they are supposed to be. Everything works printing to an .xps document or .pdf; but why doesn't it work when being sent to a physical printer?
For what it's worth, there is a DataGrid in my control and I had trouble with *-size spacing columns in the past, but they are all fixed width so I'm not sure if its related or not.
It turns out that it must have been a printer driver issue. I re-installed the driver for the same printer and after doing so everything worked correctly.
I got in direct contact with Xerox's firmware team for the specific printer and they let me know that there was firmware updates for the printer and that it could be serviced to hopefully fix it. They couldn't pin point exactly what the issue is, but the issue is now in their bug system.
When in doubt, re-install a printers driver and try printing again when you're having rendering problems. I'm not sure what invokes this bad behavior but printing to any other printer worked correctly; that's how I narrowed it down to a driver issue.

POS Application Development - Receipt Printing

I've been building a POS application for a restaurant/bar. The design part is done and for the past month I've been coding it. Everything works fine except now I need to print. I have to print to a receipt printer connected to the computer running the software and later I'll try to print in a remote printer like a kitchen one.
I've searched for help in the matter only to find that the standard for printing in these types of printers is using POS for .NET. The thing is, this is now a bit outdated or at least it hasn't had any updates since a couple of years. There's a lot of questions being asked on how to use this library and most of the answers aren't quite easy to follow. So if anybody could give a step by step help on printing like a simple phrase ("Hello World") on a receipt printer i would be very grateful. I'm using visual studio 2012 running on a 64 bit windows 7 and i'm coding WPF in c#.
I know this is an old post, but for those still looking for a solution, I can tell you what I did.
After spending many hours messing with OPOS and POS for .Net, I ended up just abandoning those and just using the built-in System.Drawing.Printing libraries. The OPOS and POS for .Net ended up being a pain to get working and ultimately didn't work as well as the built-in libraries.
I'm using an Epson TM-T20II receipt printer.
Here's some code that worked well for me.
public static void PrintReceiptForTransaction()
{
PrintDocument recordDoc = new PrintDocument();
recordDoc.DocumentName = "Customer Receipt";
recordDoc.PrintPage += new PrintPageEventHandler(ReceiptPrinter.PrintReceiptPage); // function below
recordDoc.PrintController = new StandardPrintController(); // hides status dialog popup
// Comment if debugging
PrinterSettings ps = new PrinterSettings();
ps.PrinterName = "EPSON TM-T20II Receipt";
recordDoc.PrinterSettings = ps;
recordDoc.Print();
// --------------------------------------
// Uncomment if debugging - shows dialog instead
//PrintPreviewDialog printPrvDlg = new PrintPreviewDialog();
//printPrvDlg.Document = recordDoc;
//printPrvDlg.Width = 1200;
//printPrvDlg.Height = 800;
//printPrvDlg.ShowDialog();
// --------------------------------------
recordDoc.Dispose();
}
private static void PrintReceiptPage(object sender, PrintPageEventArgs e)
{
float x = 10;
float y = 5;
float width = 270.0F; // max width I found through trial and error
float height = 0F;
Font drawFontArial12Bold = new Font("Arial", 12, FontStyle.Bold);
Font drawFontArial10Regular = new Font("Arial", 10, FontStyle.Regular);
SolidBrush drawBrush = new SolidBrush(Color.Black);
// Set format of string.
StringFormat drawFormatCenter = new StringFormat();
drawFormatCenter.Alignment = StringAlignment.Center;
StringFormat drawFormatLeft = new StringFormat();
drawFormatLeft.Alignment = StringAlignment.Near;
StringFormat drawFormatRight = new StringFormat();
drawFormatRight.Alignment = StringAlignment.Far;
// Draw string to screen.
string text = "Company Name";
e.Graphics.DrawString(text, drawFontArial12Bold, drawBrush, new RectangleF(x, y, width, height), drawFormatCenter);
y += e.Graphics.MeasureString(text, drawFontArial12Bold).Height;
text = "Address";
e.Graphics.DrawString(text, drawFontArial10Regular, drawBrush, new RectangleF(x, y, width, height), drawFormatCenter);
y += e.Graphics.MeasureString(text, drawFontArial10Regular).Height;
// ... and so on
}
Hopefully it helps someone skip all the messing around with custom drivers. :)
POS for .NET is probably the way to go.
Most receipt printer manufacturers will provide an OPOS service object.
And as this MSDN article states, POS for .NET is compatible with OPOS v1.8 service objects.
OPOS / UPOS (on which POS for .NET is based) is IMHO a poorly-designed API (designed by device manufacturers rather than application developers), but it's the best you have today.
I don't have any specific samples but the basics are the same as OPOS - you need to Open, Claim, Enable a device, then you can call its methods (such as Print). You might try looking at an OPOS sample, for example this PosPrinter1 sample, which will probably be very similar to POS for .NET.
This blog has some information about setting up POS for .NET that might be helpful.
UPDATE
Here's a VB Hello World for an OPOS printer. You first need to create a printer and add it to the registry with the required Logical Device Name = LDN. I believe the Epson ADK includes a utility to add a printer in the registry. This utility can also perform a health check on the printer to check it is installed correctly. Once you've done this, it should be easy enough to adapt the code below to POS for .NET
OPOSPOSPrinter.Open "MyPrinter" ' LDN of your printer
OPOSPOSPrinter.Claim 500 ' Timeout
OPOSPOSPrinter.DeviceEnabled = True
'- Print
OPOSPOSPrinter.PrintNormal 2, "Hello world"
'- Close the printer
If OPOSPOSPrinter.Claimed then
OPOSPOSPrinter.Release
End If
OPOSPOSPrinter.Close
.NET Printing
Printing under .NET isn't too difficult. Take a look here and on msdn.
Printing to a POS / receipt printer will be the same as printing to any other printer, assuming it is a Windows printer, network or otherwise. If you are using a serial printer, things may be a little more difficult because you will more then likely need to use manufacturer specific API's, fortunately though most good POS printers these days are fully supported by the OS.
First, you will need to add a reference to System.Printing dll to your project.
Then printing is as simple as
private void PrintText(string text)
{
var printDlg = new PrintDialog();
var doc = new FlowDocument(new Paragraph(new Run(text)));
doc.PagePadding = new Thickness(10);
printDlg.PrintDocument((doc as IDocumentPaginatorSource).DocumentPaginator, "Print Caption");
}
To use..
PrintText("Hello World");
You can also leverage the PrintDialog.PrintVisual and define your document using xaml template.
The print settings can be set using the PrintDialog properties.
Getting the printer you want to print to
private PrintQueue FindPrinter(string printerName)
{
var printers = new PrintServer().GetPrintQueues();
foreach (var printer in printers)
{
if (printer.FullName == printerName)
{
return printer;
}
}
return LocalPrintServer.GetDefaultPrintQueue();
}
A few things to keep in mind though when printing to a receipt printer, you will need to take into account formatting. More specifically you will need to consider the width of your page and how many characters you can fit on each line; this was a lot of trial and error for me, especially with different font sizes.
In most cases you don't really need to worry about paging, the printer will cut the paper automatically when it has completed your document.
If you want to print at the full speed of the printer, you will probably need to use printer-specific escape codes, and generate the "raw" output.
Have a look at Michael Buen's answer to this SO question, especially the UPDATE bit.

Fellow Oak DICOM - changing image window level

I am not an experienced programmer, just need to add a DICOM viewer to my VS2010 project. I can display the image in Windows Forms, however can't figure out how to change the window center and width. Here is my script:
DicomImage image = new DicomImage(_filename);
int maxV = image.NumberOfFrames;
sbSlice.Maximum = maxV - 1;
image.WindowCenter = 7.0;
double wc = image.WindowCenter;
double ww = image.WindowWidth;
Image result = image.RenderImage(0);
DisplayImage(result);
It did not work. I don't know if this is the right approach.
The DicomImage class was not created with the intention of it being used to implement an image viewer. It was created to render preview images in the DICOM Dump utility and to test the image compression/decompression codecs. Maybe it was a mistake to include it in the library at all?
It is difficult for me to find fault in the code as being buggy when it is being used for something far beyond its intended functionality.
That said, I have taken some time to modify the code so that the WindowCenter/WindowWidth properties apply to the rendered image. You can find these modifications in the Git repo.
var img = new DicomImage(fileName);
img.WindowCenter = 2048.0;
img.WindowWidth = 4096.0;
DisplayImage(img.RenderImage(0));
I looked at the code and it looked extremely buggy. https://github.com/rcd/fo-dicom/blob/master/DICOM/Imaging/DicomImage.cs
In the current buggy implementation setting the WindowCenter or WindowWidth properties has no effect unless Dataset.Get(DicomTag.PhotometricInterpretation) is either Monochrome1 or Monochrome2 during Load(). This is already ridiculous, but it still cannot be used because the _renderOptions variable is only set in a single place and is immediately used for the _pipeline creation (not giving you chance to change it using the WindowCenter property). Your only chance is the grayscale _renderOptions initialization: _renderOptions = GrayscaleRenderOptions.FromDataset(Dataset);.
The current solution: Your dataset should have
DicomTag.WindowCenter set appropriately
DicomTag.WindowWidth != 0.0
DicomTag.PhotometricInterpretation == Monochrome1 or Monochrome2
The following code accomplishes that:
DicomDataset dataset = DicomFile.Open(fileName).Dataset;
//dataset.Set(DicomTag.WindowWidth, 200.0); //the WindowWidth must be non-zero
dataset.Add(DicomTag.WindowCenter, "100.0");
//dataset.Add(DicomTag.PhotometricInterpretation, "MONOCHROME1"); //ValueRepresentations tag is broken
dataset.Add(new DicomCodeString(DicomTag.PhotometricInterpretation, "MONOCHROME1"));
DicomImage image = new DicomImage(dataset);
image.RenderImage();
The best solution: Wait while this buggy library is fixed.

Categories