My print is dimmed/purple?
Some users have reported that my client software is printing dimmed from certain PC's. I've spend a long time trying to figure out what's happening, and at some point I tried printing the image to a colorprinter - it turned out that what should have been gray is purple - thus the dimmed output on a b/w printer.
I've compared the configuration on clients with and without the problem and it seems that the windows printerdriver is exactly the same, the JRE is exactly the same (the problem has been observed on 1.4 + 1.5 and possibly more). It does'nt matter which printer I print to, even an ImagePrinter display the problem.
It only occurs on a few machines, and it's consistent.
I've created a little test proggy that illustrates the problem.
Usage:java TestPrint - list available printers
Usage:java TestPrint # - print on specified printer e.g. java TestPrint 1
First the main class:
/*
* TestPrint.java
*
* Created on 19-06-2007, 10:34:22
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
*
* @author ch
*/
publicclass TestPrint{
public TestPrint(){
}
publicstaticvoid main(String[] args){
new TestPrint().go(args);
}
privatevoid go(String[] args){
if (args.length == 0){
listPrinters();
}else{
testPrint(Integer.parseInt(args[0]));
}
}
privatevoid listPrinters(){
String[] printers = PrintUtilities.getConnectedPrinters();
for (int i = 0; i < printers.length; i++){
String printer = printers[i];
System.out.println(i +" : " + printer);
}
}
privatevoid testPrint(int printerNo){
java.awt.Frame frame = createFrame();
String printer =null;
try{
printer = PrintUtilities.getConnectedPrinters()[printerNo];
}catch (IndexOutOfBoundsException ie){
System.out.println("Index out of bounds, printdialog");
}
PrintUtilities.printComponent(printer, frame, javax.print.attribute.standard.OrientationRequested.LANDSCAPE, 600);
}
private Frame createFrame(){
Frame frame =new Frame();
frame.setSize(400, 400);
Color gray =new Color(241, 242, 241);
frame.setBackground(gray);
frame.setLayout(new FlowLayout());
Component c0 =new MyComponent("Ordrekonfiguration");
Component c1 =new MyComponent("Debitorkoder");
Component c2 =new MyComponent("Adresse");
Component c3 =new MyComponent("Testkunde");
frame.add(c0);
frame.add(c1);
frame.add(c2);
frame.add(c3);
frame.addWindowListener(new WindowAdapter(){
publicvoid windowClosing(WindowEvent e){
System.exit(0);
}
});
frame.setVisible(true);
return frame;
}
class MyComponentextends Component{
String label;
public MyComponent(String label){
this.label = label;
}
publicvoid paint(Graphics g){
g.setColor(Color.black);
FontMetrics ft = g.getFontMetrics();
g.drawString(label, 0, ft.getAscent());
}
@Override
public Dimension getPreferredSize(){
returnnew Dimension(200, 100);
}
}
}
Then the print-utility class
import java.awt.*;
import javax.swing.*;
import java.awt.print.*;
import java.util.*;
import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
/**
* A simple utility class that lets you very simply print
* an arbitrary component. Just pass the component to the
* PrintUtilities.printComponent. The component you want to
* print doesn't need a print method and doesn't have to
* implement any interface or do anything special at all.
* <P>
* If you are going to be printing many times, it is marginally more
* efficient to first do the following:
* <PRE>
*PrintUtilities printHelper = new PrintUtilities(theComponent, ...);
* </PRE>
* then later do printHelper.print(). But this is a very tiny
* difference, so in most cases just do the simpler
* PrintUtilities.printComponent(componentToBePrinted).
*
* 7/99 Marty Hall, http://www.apl.jhu.edu/~hall/java/
* May be freely used or adapted.
*
* 11/03 CH
* Applied resolution, orientation and scaling
*
* Notice: This class needs Java1.4
*
*/
publicclass PrintUtilitiesimplements Printable{
private Image image;
private Dimension cd;
private String printerName;
/**
* @param printerName name of printer (printservice) make sure this exists as it is not validated
* @param resolution not used!
*/
publicstaticvoid printComponent(String printerName, Component c,final OrientationRequested orientation,finalint resolution){
final PrintUtilities print =new PrintUtilities(printerName, c);
Thread t =new Thread(){
publicvoid run(){
print.go(orientation);
}
};
t.start();
}
/**
* @param printerName name of printer (printservice) make sure this exists as it is not validated
*/
public PrintUtilities(String printerName, Component componentToBePrinted){
this.printerName = printerName;
cd = componentToBePrinted.getSize();
image = componentToBePrinted.createImage(cd.width, cd.height);
Graphics g = image.getGraphics();
try{
Thread.sleep(1000);
}catch (InterruptedException ie){
}
componentToBePrinted.paint(g);
}
publicvoid go(OrientationRequested orientation){
PrintRequestAttributeSet aset =new HashPrintRequestAttributeSet();
if (orientation !=null){
aset.add(orientation);
}
aset.add(PrintQuality.HIGH);
aset.add(new JobName("PrintJob",null));
PrintService printService =null;
if (printerName !=null){
printService = getPrintService(printerName);
}
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setPrintable(this);
try{
boolean accept =true;
if (printService ==null){
accept = pj.printDialog(aset);
}else{
pj.setPrintService(printService);
}
if(accept){
pj.print(aset);
}
}catch (PrinterException pe){
System.err.println(pe);
}
}
/**
* Scale the graphics area to fit paper and ask component to draw
* into that.
*/
publicint print(Graphics g, PageFormat pageFormat,int pageIndex){
if (pageIndex > 0){
return(NO_SUCH_PAGE);
}else{
if (image !=null && cd.width > 0 && cd.height > 0){
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
double scale = 0;
double scaleX = pageFormat.getImageableWidth() / cd.width;
double scaleY = pageFormat.getImageableHeight() / cd.height;
// use the smaller scaling
// Use the same scaling on x,y to get a better result
if (scaleY < scaleX){
scale = scaleY;
}else{
scale = scaleX;
}
g2d.scale(scale, scale);
Rectangle rect = g2d.getClipRect();
g2d.drawImage(image, 0, 0, cd.width, cd.height,null);
}else{
System.out.println("Can't print - empty image");
g.drawString("Can't print - empty image", 100, 100);
}
return(PAGE_EXISTS);
}
}
/**
* @return List of available printers
* Only call this method from a Java1.4 JVM
*/
publicstaticsynchronized String[] getConnectedPrinters(){
String[] strPrinterList;
PrintService[] printerList = PrinterJob.lookupPrintServices();
if (printerList !=null && printerList.length > 0){
strPrinterList =new String[printerList.length];
for (int i = 0; i < printerList.length; i++){
strPrinterList[i] =new String(printerList[i].getName());
}
}else{
strPrinterList =new String[0];
}
return strPrinterList;
}
/**
* @param printer name of printer to retrive printerservice for
* @return printerservice of printer with given name
*/
privatestatic PrintService getPrintService(String printer){
PrintService locatedService =null;
PrintService[] printerList = PrinterJob.lookupPrintServices();
if (printerList !=null && printerList.length > 0){
for (int i = 0; i < printerList.length; i++){
if (printer.equalsIgnoreCase(printerList[i].getName())){
locatedService = printerList[i];
break;
}
}
}
return locatedService;
}
}
Here is a imagedump of two outputs, the one on the left is correct. Please notice that the purple colors on the right have been altered so the RGB values does not exactly reflect the image on the printer.
http://imageload.dk/files/2be6083125d4d8f8d4a8bc08588cf283.jpg

