初遇 DPI

pdi-tips

DPI

维基

(英语:Dots Per Inch,每英寸点数)是一个量度单位,用于点阵数位影像,意思是指每一英寸长度中,取样或可显示或输出点的数目。

单位转换

1 英寸=2.54 厘米

1点 = 1/72英寸

1点 = 1/300英寸

问题

印刷业定制的图片剪辑功能,需要以 40 * 40 CM 或其他宽高规格来处理原始图片。请问应该怎么做?

解答

首先,印刷的通常分辨率为300dpi,就是一英寸300像素。即 DPI = 300;

所以,

假设宽度为 width,高度为 height,单位: CM;

得到,图片缩放后的最终宽高,

宽: width / 2.54 *DPI

高: height / 2.54 * DPI

代码

原图需要按指定宽高比例,配合页面选框进行裁剪。

裁剪后的图片,再进行以下步骤处理。

获取图片对象

1
File file = new File(filePath.toString());

转换获取 BufferedImage 对象

1
BufferedImage img = ImageIO.read(file)

获取图片宽高

1
2
double sourceW = img.getWidth();
double sourceH = img.getHeight();

最终的宽高

1
2
3
4
5
int DPI = 300,
width = 30, // cm
height = 30; // cm
double targetW = width / 2.54 * DPI;
double targetH = height / 2.54 * DPI;

计算压缩比(等比压缩)

1
2
3
4
5
6
7
8
9
10
double sx = (double) targetW / sourceW;
double sy = (double) targetH / sourceH;

if (sx > sy) {
	sx = sy;
	targetW = (int) (sx * source.getWidth());
} else if (sx < sy) {
	sy = sx;
	targetH = (int) (sy * source.getHeight());
}

空白画布

1
2
String type = "PNG";
BufferedImage target = new BufferedImage(targetW, targetH, type);

绘制图片

1
2
3
Graphics2D g = target.createGraphics();  	g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
g.dispose();

转换 byte[]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
byte[] result = null;
ByteArrayOutputStream outStream = null;
try {
	if (image != null) {
		outStream = new ByteArrayOutputStream();
		ImageIO.write(image,format,outStream);
		result = outStream.toByteArray();
		}
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		if (outStream != null) {
			try {
				outStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	return result;

存放新图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
BufferedOutputStream stream = null;
	try {
		File file = new File(outputFile);
		if (file.exists() && !isCover) {
			return Boolean.FALSE; // 源文件已经存在
		}
		FileOutputStream out = new FileOutputStream(file);
		stream = new BufferedOutputStream(out);
		stream.write(b);
	} catch (Exception e) {
		String fullStackTrace = ExceptionUtils.getStackTrace(e);
		LOGGER.error(fullStackTrace);
		return Boolean.FALSE;
	} finally {
		if (stream != null) {
			try {
				stream.close();
			} catch (IOException e) {
				String fullStackTrace = ExceptionUtils.getStackTrace(e);
				LOGGER.error(fullStackTrace);
				return Boolean.FALSE;
			}
		}
	}
	return Boolean.TRUE;

PS. 遇到新问题时,不要害怕,先分析再 Coding。