我需要在 4"x 6"纸(也称为 4r)上打印 1800 x 1200 像素、300 dpi 的图像
我尝试过的
我创建了一个 PrintRequestAttributeSet 来处理我的 PrintableArea(4 x 6)、Printer print DPI、Orientation。我在底部附上了一个 MCVE。
问题
虽然代码有效,但我得到了一个具有以下属性的 PageFormat(对于我的打印机):
x= 12.0
y= 12.32
w= 276.0
h= 419.67
宽度和高度少了一点,因为我的打印机不支持零边距。 (这是我考虑过的。如果有人知道除此之外我可以强制零 margin 的方法,请告诉我)
我提供的 边距为 0,因为这些图像将通过支持零边距的打印机(Photobooth 打印机)打印。
aset.add(new MediaPrintableArea(0, 0, 4, 6, MediaPrintableArea.INCH));
根据需要,包括边距在内的可打印区域大约为 4 x 6。当我缩放图像以在可打印区域内打印时出现问题。
由于图像是 1800 x 1200,它支持 3:2 的纵横比,这意味着创建图像以打印在 4 x 6 的纸张上(旋转和缩放后)。 For Reference.
现在,由于 PageFormat 的 pageWidth 和 pageHeight 不能被 ImageWidth 和 ImageHeight 整除。我遇到了缩放问题。
注意:我旋转图像是因为它必须打印在 4 x 6 而不是 6 x 4 上。
本应占用 4 x 6 空间的图像占用了接近 4 x 5 的空间。图像尺寸也大幅减小。
我该如何克服这个问题?
代码
请在此处找到 MCVE:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.PrintQuality;
import javax.print.attribute.standard.PrinterResolution;
public class ImgPrinter implements Printable {
Image img;
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
throws PrinterException {
Graphics2D g2d = (Graphics2D) graphics;
g2d.translate((int) (pageFormat.getImageableX()),
(int) (pageFormat.getImageableY()));
if (pageIndex == 0) {
double pageWidth = pageFormat.getImageableWidth();
double pageHeight = pageFormat.getImageableHeight();
/**
* Swapping width and height, coz the image is later rotated
*/
double imageWidth = img.getHeight(null);
double imageHeight = img.getWidth(null);
double scaleX = pageWidth / imageWidth;
double scaleY = pageHeight / imageHeight;
g2d.scale(scaleX, scaleY);
g2d.rotate(Math.toRadians(90), img.getWidth(null) / 2,
img.getHeight(null) / 2);
g2d.drawImage(img, 0, 0, null);
return Printable.PAGE_EXISTS;
}
return Printable.NO_SUCH_PAGE;
}
public void printPage(String file, String size) {
try {
Image img = ImageIO.read(new File(file));
this.img = img;
PrintRequestAttributeSet aset = createAsetForMedia(size);
PrinterJob pj = PrinterJob.getPrinterJob();
PageFormat pageFormat = pj.getPageFormat(aset);
pj.setPrintable(this, pageFormat);
pj.print();
} catch (PrinterException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private PrintRequestAttributeSet createAsetForMedia(String size) {
PrintRequestAttributeSet aset = null;
try {
aset = new HashPrintRequestAttributeSet();
aset.add(PrintQuality.NORMAL);
aset.add(OrientationRequested.PORTRAIT);
/**
* Suggesting the print DPI as 300
*/
aset.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
/**
* Setting the printable area and the margin as 0
*/
if (size.equals("3r")) {
aset.add(new MediaPrintableArea(0, 0, 3, 5,
MediaPrintableArea.INCH));
} else if (size.equals("4r")) {
aset.add(new MediaPrintableArea(0, 0, 4, 6,
MediaPrintableArea.INCH));
} else if (size.equals("5r")) {
aset.add(new MediaPrintableArea(0, 0, 5, 7,
MediaPrintableArea.INCH));
} else if (size.equals("6r")) {
aset.add(new MediaPrintableArea(0, 0, 6, 8,
MediaPrintableArea.INCH));
}
} catch (Exception e) {
e.printStackTrace();
}
return aset;
}
public static void main(String[] args) {
new ImgPrinter().printPage("/Some_URL/sam.jpg",
"4r");
}
}
要运行该程序,只需向主程序提供 1800x1200 图像路径,它就会打印到默认打印机。
最佳答案
让我担心的事情...
Graphics 上下文的比例/旋转,而不是先复制它或事后重置它。这实际上可能会影响后续渲染,因为 printable 可能会被多次调用...Graphics2D#scale。这确实不是最好的质量,通常也不是那么快。参见 The Perils of Image.getScaledInstance() .我也更喜欢使用 AffineTransform,但那只是我...print 方法可能会被多次调用以打印单个页面,每次缩放图像的成本很高,相反,您应该缩放一次并重新使用缩放后的结果。0x0 的位置。Graphics 上下文时,原点会发生变化,因此原点不会位于上角/左角,在这种情况下,它将变为上角/右角。现在你知道为什么我会单独旋转图像而不是尝试弄乱 Graphics 上下文 :P我“认为”正在发生的事情是在坐标的缩放、旋转和操作(交换高度和宽度)之间,事情变得一团糟……但坦率地说,我不会乱搞的当我有更好的解决方案时...
下面的例子使用了一堆个人库代码,所以有些可能有点复杂,但我对其他东西使用了单独的功能,所以它结合得很好......
因此,从 7680x4800 的图像开始,这会生成 423x264 的缩放图像
(红色边框仅为视觉指南,用于将结果转储为 PDF 以节省纸张;))
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.PrintQuality;
import javax.print.attribute.standard.PrinterResolution;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ImgPrinter implements Printable {
BufferedImage img;
BufferedImage scaled;
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
throws PrinterException {
int result = NO_SUCH_PAGE;
Graphics2D g2d = (Graphics2D) graphics.create();
g2d.translate((int) (pageFormat.getImageableX()), (int) (pageFormat.getImageableY()));
if (pageIndex == 0) {
double pageWidth = pageFormat.getImageableWidth();
double pageHeight = pageFormat.getImageableHeight();
if (scaled == null) {
// Swap the width and height to allow for the rotation...
System.out.println(pageWidth + "x" + pageHeight);
scaled = getScaledInstanceToFit(
img,
new Dimension((int)pageHeight, (int)pageWidth));
System.out.println("In " + img.getWidth() + "x" + img.getHeight());
System.out.println("Out " + scaled.getWidth() + "x" + scaled.getHeight());
}
double imageWidth = scaled.getWidth();
double imageHeight = scaled.getHeight();
AffineTransform at = AffineTransform.getRotateInstance(
Math.toRadians(90),
pageWidth / 2d,
pageHeight / 2d
);
AffineTransform old = g2d.getTransform();
g2d.setTransform(at);
double x = (pageHeight - imageWidth) / 2d;
double y = (pageWidth - imageHeight) / 2d;
g2d.drawImage(
scaled,
(int)x,
(int)y,
null);
g2d.setTransform(old);
// This is not affected by the previous changes, as those were made
// to a different copy...
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, (int)pageWidth - 1, (int)pageHeight - 1);
result = PAGE_EXISTS;
}
g2d.dispose();
return result;
}
public void printPage(String file, String size) {
try {
img = ImageIO.read(new File(file));
PrintRequestAttributeSet aset = createAsetForMedia(size);
PrinterJob pj = PrinterJob.getPrinterJob();
PageFormat pageFormat = pj.getPageFormat(aset);
pj.setPrintable(this, pageFormat);
if (pj.printDialog()) {
pj.print();
}
} catch (PrinterException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private PrintRequestAttributeSet createAsetForMedia(String size) {
PrintRequestAttributeSet aset = null;
try {
aset = new HashPrintRequestAttributeSet();
aset.add(PrintQuality.NORMAL);
aset.add(OrientationRequested.PORTRAIT);
/**
* Suggesting the print DPI as 300
*/
aset.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
/**
* Setting the printable area and the margin as 0
*/
if (size.equals("3r")) {
aset.add(new MediaPrintableArea(1, 1, 3, 5,
MediaPrintableArea.INCH));
} else if (size.equals("4r")) {
aset.add(new MediaPrintableArea(1, 1, 4, 6,
MediaPrintableArea.INCH));
} else if (size.equals("5r")) {
aset.add(new MediaPrintableArea(1, 1, 5, 7,
MediaPrintableArea.INCH));
} else if (size.equals("6r")) {
aset.add(new MediaPrintableArea(1, 1, 6, 8,
MediaPrintableArea.INCH));
}
} catch (Exception e) {
e.printStackTrace();
}
return aset;
}
public static BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {
double scaleFactor = getScaleFactorToFit(img, size);
return getScaledInstance(img, scaleFactor);
}
public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
}
public static double getScaleFactorToFit(BufferedImage img, Dimension size) {
double dScale = 1;
if (img != null) {
int imageWidth = img.getWidth();
int imageHeight = img.getHeight();
dScale = getScaleFactorToFit(new Dimension(imageWidth, imageHeight), size);
}
return dScale;
}
public static double getScaleFactorToFit(Dimension original, Dimension toFit) {
double dScale = 1d;
if (original != null && toFit != null) {
double dScaleWidth = getScaleFactor(original.width, toFit.width);
double dScaleHeight = getScaleFactor(original.height, toFit.height);
dScale = Math.min(dScaleHeight, dScaleWidth);
}
return dScale;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
return (double) iTargetSize / (double) iMasterSize;
}
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint) {
BufferedImage imgScale = img;
int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);
if (dScaleFactor <= 1.0d) {
imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint);
} else {
imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint);
}
return imgScale;
}
protected static BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint) {
// System.out.println("Scale down...");
int type = (img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
if (targetHeight > 0 || targetWidth > 0) {
int w = img.getWidth();
int h = img.getHeight();
do {
if (w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
} else {
ret = new BufferedImage(1, 1, type);
}
return ret;
}
protected static BufferedImage getScaledUpInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w = img.getWidth();
int h = img.getHeight();
do {
if (w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (h < targetHeight) {
h *= 2;
if (h > targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
tmp = null;
} while (w != targetWidth || h != targetHeight);
return ret;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new ImgPrinter().printPage("/Volumes/Disk02/Dropbox/Wallpapers/animepaper.net_wallpaper_art_anime_aria_duanwu_festival_205050_wonderngo_7680x4800-a8aecc9c.jpg",
"4r");
}
});
}
}
你知道什么会更容易,以横向模式打印页面以开始 :P
关于java - 使用 Java 在 4 x 6 纸上打印 1800 x 1200 图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27273402/
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.
Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur
在Java中,可以像这样从一个字符串创建一个IO流:Readerr=newStringReader("mytext");我希望能够在Ruby中做同样的事情,这样我就可以获取一个字符串并将其视为一个IO流。 最佳答案 r=StringIO.new("mytext")和here'sthedocumentation. 关于java-Java的StringReader的Ruby等价物是什么?,我们在StackOverflow上找到一个类似的问题: https://st