Borderless printing - java

I'm trying to write a photobooth program but I'm having a hard time making a borderless print. I'm very close but the image does not fill a 4" x 6" print. I would appreciate any tips on achieving a borderless print.
Cheers!
final BufferedImage img = ImageIO.read(new File(image));
// Assuming that images are going to be 300 DPI
PrinterResolution pr = new PrinterResolution(300, 300,
PrinterResolution.DPI);
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
pras.add(pr);
// Set print job so the image name shows (in the print queue)
this.pj.setJobName(new File(image).getName());
PageFormat pf = this.pj.getPageFormat(null);
Paper paper = pf.getPaper();
paper.setSize(4 * 72, 6 * 72);
paper.setImageableArea(
0.0, 0.0,
paper.getWidth(), paper.getHeight()
);
if(img.getWidth(null) > img.getHeight(null))
pf.setOrientation(PageFormat.LANDSCAPE);
else
pf.setOrientation(PageFormat.PORTRAIT);
pf.setPaper(paper);
// Create the page
this.pj.setPrintable(new Printable() {
public int print(Graphics g, PageFormat pf, int i) throws
PrinterException {
if (i != 0)
return NO_SUCH_PAGE;
double width = img.getWidth(null);
double height = img.getHeight(null);
double w = Math.floor(pf.getImageableWidth() -
pf.getImageableX()) / (width * 1.0);
double h = Math.floor(pf.getImageableHeight() -
pf.getImageableY()) / (height * 1.0);
double scale = Math.min(w, h);
Graphics2D g2 = (Graphics2D) g;
g2.translate(0, 0);
g2.scale(scale, scale);
g2.drawImage(img, 0, 0, (int)width, (int)height, null);
return PAGE_EXISTS;
}
}, this.pj.validatePage(pf));
// Get number of copies
int nCopies = SetPrintQuantity.getPrintQuantity(new File(image));
// Print
if(nCopies != 0)
for(int i = 0; i < nCopies; i++)
this.pj.print(pras);
System.out.println(nCopies + ((nCopies == 1) ? " copy" : " copies"));
this.pj = PrinterJob

I have been fighting the same problems for a while now. Here is my solution:
Determine the actual page size of your printer:
final PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintService(ps);
final PageFormat pf = printJob.defaultPage();
System.out.println("Printer Page width=" + pf.getWidth() + " height=" + pf.getHeight());
For my HiTi P720L Photo Printers with 4"x6" paper it was actually 4.133"x6.147".
Create and set a new Paper object with the full page size and full imageable area:
final Paper paper = new Paper();
paper.setSize(pageWidth * 72.0f, pageHeight * 72.0f);
paper.setImageableArea(0.0, 0.0, paper.getWidth(), paper.getHeight());
pf.setPaper(paper);
Then the final trick, draw to x/y coordinates outside the range. In my case I had to scale the x coordinates by 10% and translate the x coordinate by -55 (placing it into negative x values).
printJob.setPrintable(new Printable() {
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
Graphics2D g2 = (Graphics2D) graphics;
final double xScale = 1.1;
final double xTranslate = -55;
final double yScale = 1;
final double yTranslate = 0;
final double widthScale = (pageFormat.getWidth() / image.getWidth()) * xScale;
final double heightScale = (pageFormat.getHeight() / image.getHeight()) * yScale;
System.out.println("Setting scale to " + widthScale + "x" + heightScale);
final AffineTransform at = AffineTransform.getScaleInstance(widthScale, heightScale);
System.out.println("Setting translate to " + xTranslate + "x" + yTranslate);
at.translate(xTranslate, yTranslate);
if (pageIndex != 0) {
return NO_SUCH_PAGE;
}
g2.drawRenderedImage(image, at);
return PAGE_EXISTS;
}
}, pf);

Related

Rotating a bufferedImage 90 degrees

I am looking to rotate an image that is loaded from files by 90 degrees. I have the code but when I use it, I am given an error saying that the coordinates are out of bounds. Any help would be appreciated.
Here is the method I have written so far:
public void rotateImage(OFImage image) {
if (currentImage != null) {
int width = image.getWidth();
int height = image.getHeight();
OFImage newImage = new OFImage(width, height);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
Color col = image.getPixel(i, j);
newImage.setPixel(height - j - 2, i, col);
}
}
image = newImage;
}
}
When you rotate the image by a certain angle, the resulting image becomes larger than the original one. The maximum image size is obtained when rotated by 45 degrees:
When creating a new image, you have to set its dimensions according to the rotated size:
public BufferedImage rotateImage(BufferedImage image, double angle) {
double radian = Math.toRadians(angle);
double sin = Math.abs(Math.sin(radian));
double cos = Math.abs(Math.cos(radian));
int width = image.getWidth();
int height = image.getHeight();
int nWidth = (int) Math.floor((double) width * cos + (double) height * sin);
int nHeight = (int) Math.floor((double) height * cos + (double) width * sin);
BufferedImage rotatedImage = new BufferedImage(
nWidth, nHeight, BufferedImage.TYPE_INT_ARGB);
// and so on...
return rotatedImage;
}
See also: Rotate a buffered image in Java

Printing to a Dymo labelprinter from Java

I'm trying to print a label on my Dymo LabelWriter 450, but am having a hard time.
The issue I am dealing with now is that I can't even seem to fill the entire label, there seems to be a left margin of about 0.6mm that I don't get when I print using the Dymo software.
Ideally I would use an SDK, but I am unable to find a Dymo Java SDK.
This is the result I'm looking for
This is what I've got so far
I modified some code from this answer to get to this result.
public class PrinterTest {
public static void main(String[] args) {
PrinterJob printerJob = PrinterJob.getPrinterJob();
if (printerJob.printDialog()) {
PageFormat pageFormat = printerJob.defaultPage();
Paper paper = pageFormat.getPaper();
double width = fromCMToPPI(1.9);
double height = fromCMToPPI(4.5);
double horizontalMargin = fromCMToPPI(0.25);
double verticalMargin = fromCMToPPI(0.1);
paper.setSize(width, height);
paper.setImageableArea(
horizontalMargin,
verticalMargin,
width,
height);
pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE);
pageFormat.setPaper(paper);
printerJob.setPrintable(new MyPrintable(), pageFormat);
try {
printerJob.print();
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
}
private static double fromCMToPPI(double cm) {
return toPPI(cm * 0.393700787);
}
private static double toPPI(double inch) {
return inch * 72d;
}
public static class MyPrintable implements Printable {
#Override
public int print(Graphics graphics, PageFormat pageFormat,
int pageIndex) {
System.out.println(pageIndex);
int result = NO_SUCH_PAGE;
if (pageIndex < 1) {
Graphics2D g2d = (Graphics2D) graphics;
double width = pageFormat.getImageableWidth();
double height = pageFormat.getImageableHeight();
double x = pageFormat.getImageableX();
double y = pageFormat.getImageableY();
System.out.println("x = " + x);
System.out.println("y = " + y);
g2d.translate((int) pageFormat.getImageableX(), (int) pageFormat.getImageableY());
g2d.draw(new Rectangle2D.Double(x, y, width - x, height - y));
FontMetrics fm = g2d.getFontMetrics();
g2d.drawString("AxB", Math.round(x), fm.getAscent());
result = PAGE_EXISTS;
}
return result;
}
}
}
If there is an SDK available that I missed, I would love to know where to find it. Otherwise, how can I get rid of this left margin so that I can actually fit everything on the label?
Thanks!

How to fit width of a page when printing in java

I can print any component smartly with a footer by this code. Its working smartly.
public class MultiPagePrintable implements Printable {
private JComponent component;
private int lastPage = 0;
private double yOffset;
private Font footerFont;
public MultiPagePrintable(JComponent component) {
this.component = component;
footerFont = new Font("Arial", Font.BOLD, 24);
}
#Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
int result = NO_SUCH_PAGE;
String name = "I be mighty!";
String page = Integer.toString(pageIndex);
FontMetrics fm = graphics.getFontMetrics(footerFont);
double footerHeight = fm.getHeight() + 4;
double height = pageFormat.getImageableHeight() - footerHeight;
component.setSize(component.getPreferredSize());
if (lastPage != pageIndex) {
lastPage = pageIndex;
yOffset = height * pageIndex;
if (yOffset > component.getHeight()) {
yOffset = -1;
}
}
if (yOffset >= 0) {
Graphics2D g2d = (Graphics2D) graphics.create();
g2d.translate((int) pageFormat.getImageableX(),
(int) pageFormat.getImageableY());
g2d.translate(0, -yOffset);
component.printAll(g2d);
g2d.translate(0, +yOffset);
Shape footerArea = new Rectangle2D.Double(0, height, pageFormat.getImageableWidth(), footerHeight);
g2d.setColor(Color.WHITE);
g2d.fill(footerArea);
g2d.setColor(Color.RED);
g2d.draw(footerArea);
g2d.setColor(Color.BLACK);
g2d.translate(0, (pageFormat.getImageableHeight() - footerHeight));
float x = 2;
float y = (float)((footerHeight - fm.getHeight()) / 2d);
g2d.drawString(name, x, y + fm.getAscent());
x = (float)(pageFormat.getImageableWidth() - fm.stringWidth(page) - 2);
g2d.drawString(page, x, y + fm.getAscent());
g2d.dispose();
result = PAGE_EXISTS;
}
return result;
}
}
But problem is, it can't scale component width to fit page. However i don't want to fit height. Because this code can already print multiple page. and i need it.
You want to scale the Graphics2D:
g2d.translate(0, -yOffset);
double width = pageFormat.getImageableWidth();
double scale = Math.min(width / component.getWidth(),
height / component.getHeight());
if (scale < 1) {
AffineTransform oldTransform = g2d.getTransform();
g2d.scale(scale, scale);
component.printAll(g2d);
g2d.setTransform(oldTransform);
} else {
component.printAll(g2d);
}
g2d.translate(0, +yOffset);
I'm not sure what you mean by "I don't want to fit height" but you can always ignore the height, if you want:
g2d.translate(0, -yOffset);
double width = pageFormat.getImageableWidth();
double scale = width / component.getWidth();
if (scale < 1) {
AffineTransform oldTransform = g2d.getTransform();
g2d.scale(scale, scale);
component.printAll(g2d);
g2d.setTransform(oldTransform);
} else {
component.printAll(g2d);
}
g2d.translate(0, +yOffset);

Java2D Image Rotation Issue

I am using following code to rotate an given image.
public int getImageWidth(BufferedImage img) {
if (rotate == Rotate.UPSIDE_DOWN || rotate == Rotate.ABOUT_CENTER)
return img.getWidth();
else
return img.getHeight();
}
public int getImageHeight(BufferedImage img) {
if (rotate == Rotate.UPSIDE_DOWN || rotate == Rotate.ABOUT_CENTER)
return img.getHeight();
else
return img.getWidth();
}
This is the Rotation enums
public enum Rotate {
DOWN, UP, UPSIDE_DOWN, ABOUT_CENTER;
}
Actual rotation method
public BufferedImage rotateImage(BufferedImage source, int x, int y,
float orientation) throws Exception {
int newWidth = getImageWidth(source);
int newHeight = getImageHeight(source);
int cWidth = newWidth / 2;
int cHeight = newHeight / 2;
int imgType = source.getType() == 0 ? 5 : source.getType();
BufferedImage result = new BufferedImage(getImageWidth(source),
getImageHeight(source),imgType);
Graphics2D g2 = result.createGraphics();
if (rotate == Rotate.DOWN) {
g2.translate(x + cHeight, y + cWidth);
g2.rotate(Math.toRadians(90));
g2.drawImage(source, 0, 0, newWidth, newHeight, null);
} else if (rotate == Rotate.UP) {
g2.translate(x + cHeight, y + cWidth);
g2.rotate(Math.toRadians(-90));
g2.drawImage(source, 0, 0, newWidth, newHeight, null);
} else if (rotate == Rotate.UPSIDE_DOWN) {
g2.translate(x + cWidth, y + cHeight);
g2.rotate(Math.toRadians(180));
g2.drawImage(source, 0, 0, newWidth, newHeight, null);
} else if (rotate == Rotate.ABOUT_CENTER) {
Rectangle r = new Rectangle(x, y, newWidth, newHeight);
g2.setClip(r);
AffineTransform original = g2.getTransform();
AffineTransform at = new AffineTransform();
at.concatenate(original);
at.rotate(orientation, x + cWidth, y + cHeight);
g2.setTransform(at);
g2.drawImage(source, 0, 0, newWidth, newHeight, null);
g2.setTransform(original);
}
g2.dispose();
g2 = null;
return result;
}
The client code
// rotate derived & filtered image to 90 degree
// using Affine transform
setRotate(Rotate.UP);
BufferedImage rSubImage = rotateImage(fSubImage, 0, 0, -90);
Now the following is an source image,
When i rotate this image using above code , the result is very strange
What did i do wrong ?
also the quality is lost after rotation , please notice it.
I think the solution is to use AffineTranform, translating the Image to reamin in the center. I modified your code and tested it, for me it works:
public BufferedImage rotateImage(BufferedImage source, int x, int y,
float orientation) throws Exception {
int newWidth = getImageWidth(source);
int newHeight = getImageHeight(source);
int imgType = source.getType() == 0 ? 5 : source.getType();
BufferedImage result = new BufferedImage(getImageWidth(source),
getImageHeight(source), imgType);
if (rotate == Rotate.DOWN) {
AffineTransform tranform = new AffineTransform();
tranform.translate(newWidth / 2, newHeight / 2);
tranform.rotate(Math.toRadians(90));
tranform.translate(-source.getWidth()/2, -source.getHeight()/2);
Graphics2D g2d = result.createGraphics();
g2d.drawImage(source, tranform, null);
} else if (rotate == Rotate.UP) {
AffineTransform tranform = new AffineTransform();
tranform.translate(newWidth / 2, newHeight / 2);
tranform.rotate(Math.toRadians(-90));
tranform.translate(-source.getWidth()/2, -source.getHeight()/2);
Graphics2D g2d = result.createGraphics();
g2d.drawImage(source, tranform, null);
} else if (rotate == Rotate.UPSIDE_DOWN) {
AffineTransform tranform = new AffineTransform();
tranform.translate(newWidth / 2, newHeight / 2);
tranform.rotate(Math.toRadians(180));
tranform.translate(-source.getWidth()/2, -source.getHeight()/2);
Graphics2D g2d = result.createGraphics();
g2d.drawImage(source, tranform, null);
} else if (rotate == Rotate.ABOUT_CENTER) {
//......
}
return result;
}
Hope it helps!

Using PrinterJob to print an Image (Graphics2D)

Is there a way I can rig a PrinterJob in Java to NOT actually print to a printer so that I can get the graphics objects for each page? I tried setting the PrintService to null, but Java wouldn't allow that.
This is so that I can retrieve an accurate Print Preview for the document without essentially rebuilding PrinterJobs functions from the ground-up in a different context.
Here's the code for the print function in my program:
public int print(Graphics graphics, PageFormat pageFormat, int page) throws PrinterException {
deepCopyString = string;
FontMetrics metrics = graphics.getFontMetrics(font);
int lineHeight = metrics.getHeight();
arrangePage(graphics, pageFormat, metrics);
if (page > pageBreaks.length){
return NO_SUCH_PAGE;
}
Graphics2D g = (Graphics2D) graphics;
g.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
g.setFont(font);
int begin = (page == 0) ? 0 : pageBreaks[page-1];
int end = (page == pageBreaks.length) ? lines.length : pageBreaks[page];
int y = 0;
int x = 0;
for (int line = begin; line < end; line++){
x = 0;
y += lineHeight;
checkSyntax(line);
String l = lines[line];
for (int c = 0; c < l.length(); c++){
applySyntax(c, line);
metrics = graphics.getFontMetrics(font);
String ch = Character.toString(l.charAt(c));
g.setFont(font);
g.drawString(ch, x, y);
x += metrics.charWidth(l.charAt(c));
//System.out.println(c + "/"+l.length());
}
//g.drawString(lines[line], 0, y);
}
reset();
records.add(g);
return PAGE_EXISTS;
}
You can already see that the Graphics objects are recorded so that I can paint them in another component, but it's rather useless seeing as it will go ahead and send these to my printer before the record can be completed.
This may be a bad idea in general, and I'm pretty new to printing. If this is seriously a bad way to go about this, feel free to direct me to a source that'll explain a better way.
Basically, you want to create you own Graphics context to which you can paint. You also need to construct a PageFormat that can be past to the print method.
public class TestPrint implements Printable {
private BufferedImage background;
public static final float DPI = 72;
public static void main(String[] args) {
new TestPrint();
}
public TestPrint() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
try {
background = ImageIO.read(new File("C:/Users/shane/Dropbox/MegaTokyo/MgkGrl_Yuki_by_fredrin.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
float width = cmToPixel(21f, DPI);
float height = cmToPixel(29.7f, DPI);
Paper paper = new Paper();
float margin = cmToPixel(1, DPI);
paper.setImageableArea(margin, margin, width - (margin * 2), height - (margin * 2));
PageFormat pf = new PageFormat();
pf.setPaper(paper);
BufferedImage img = new BufferedImage(Math.round(width), Math.round(height), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle2D.Float(0, 0, width, height));
try {
g2d.setClip(new Rectangle2D.Double(pf.getImageableX(), pf.getImageableY(), pf.getImageableWidth(), pf.getImageableHeight()));
print(g2d, pf, 0);
} catch (PrinterException ex) {
ex.printStackTrace();
}
g2d.dispose();
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel(new ImageIcon(img)));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public float cmToPixel(float cm, float dpi) {
return (dpi / 2.54f) * cm;
}
public int print(Graphics graphics, PageFormat pageFormat, int page) throws PrinterException {
if (page > 0) {
return NO_SUCH_PAGE;
}
Graphics2D g = (Graphics2D) graphics;
g.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
if (background != null) {
int x = (int)Math.round((pageFormat.getImageableWidth() - background.getWidth()) / 2f);
int y = (int)Math.round((pageFormat.getImageableHeight() - background.getHeight()) / 2f);
g.drawImage(background, x, y, null);
}
g.setColor(Color.BLACK);
g.draw(new Rectangle2D.Double(0, 0, pageFormat.getImageableWidth() - 1, pageFormat.getImageableHeight() - 1));
return PAGE_EXISTS;
}
}
Now, obviously, there are going to be difference to what is printed to the screen and what's printed to the printer, because we're not actually using the same hardware device, but the basic concept applies

Categories