Java PDFBox-获取旋转图像的边界框
我正在使用PDFBox并尝试旋转图像,使其在屏幕上正确定位。我使用的设计编辑器输出以下关于图像的有用信息 图像边界框左上角坐标我使用左下角坐标来更好地适应PDFBox坐标空间 以度为单位的图像旋转 图像宽度和高度 翻译似乎已关闭Java PDFBox-获取旋转图像的边界框,java,image,math,pdfbox,Java,Image,Math,Pdfbox,我正在使用PDFBox并尝试旋转图像,使其在屏幕上正确定位。我使用的设计编辑器输出以下关于图像的有用信息 图像边界框左上角坐标我使用左下角坐标来更好地适应PDFBox坐标空间 以度为单位的图像旋转 图像宽度和高度 翻译似乎已关闭 // Rotation AffineTransform rotation = new AffineTransform(); rotation.rotate(Math.toRadians(360 - element.getAngle()), element.get
// Rotation
AffineTransform rotation = new AffineTransform();
rotation.rotate(Math.toRadians(360 - element.getAngle()),
element.getLeft() + scaledWidth/2,
adjustedYPos + scaledHeight/2);
stream.transform(new Matrix(rotation));
// Position & scale
AffineTransform mat = new AffineTransform(scaledWidth,
0,
0,
scaledHeight,
element.getLeft(),
adjustedYPos);
// Draw the final image
stream.drawImage(pdfImage, new Matrix(mat));
旋转基于图像中心作为定位点。您可以使用以下代码正确定位图像:
void placeImage(PDDocument document, PDPage page, PDImageXObject image, float bbLowerLeftX, float bbLowerLeftY, float width, float height, float angle) throws IOException {
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true) ) {
float bbWidth = (float)(Math.abs(Math.sin(angle))*height + Math.abs(Math.cos(angle))*width);
float bbHeight = (float)(Math.abs(Math.sin(angle))*width + Math.abs(Math.cos(angle))*height);
contentStream.transform(Matrix.getTranslateInstance((bbLowerLeftX + .5f*bbWidth), (bbLowerLeftY + .5f*bbHeight)));
contentStream.transform(Matrix.getRotateInstance(angle, 0, 0));
contentStream.drawImage(image, -.5f*width, -.5f*height, width, height);
}
}
PDPage page = ...;
PDRectangle mediaBox = page.getMediaBox();
float bbLowerLeftX = 50;
float bbLowerLeftY = 100;
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page) ) {
contentStream.moveTo(bbLowerLeftX, mediaBox.getLowerLeftY());
contentStream.lineTo(bbLowerLeftX, mediaBox.getUpperRightY());
contentStream.moveTo(mediaBox.getLowerLeftX(), bbLowerLeftY);
contentStream.lineTo(mediaBox.getUpperRightX(), bbLowerLeftY);
contentStream.stroke();
}
PDImageXObject image = PDImageXObject.createFromByteArray(document, IOUtils.toByteArray(resource), "Image");
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, image.getWidth(), image.getHeight(), (float)(Math.PI/4));
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .5f*image.getWidth(), .5f*image.getHeight(), 0);
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .25f*image.getWidth(), .25f*image.getHeight(), (float)(9*Math.PI/8));
实用方法
此方法接受坐标,因为它们在PDF上下文中是有意义的,即坐标值和尺寸根据给定页面的默认用户空间坐标系y值向上递增,原点在左下角任意,但通常在左下角,边界框由左下角给定,数学中以逆时针弧度表示的角度
但是,如果需要不同的参数,可以相当容易地调整该方法。例如,如果获取边界框的左上角而不是左下角,则只需减去在方法中确定为bbHeight的边界框高度,即可计算此处使用的左下y坐标
您可以这样使用此方法:
void placeImage(PDDocument document, PDPage page, PDImageXObject image, float bbLowerLeftX, float bbLowerLeftY, float width, float height, float angle) throws IOException {
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true) ) {
float bbWidth = (float)(Math.abs(Math.sin(angle))*height + Math.abs(Math.cos(angle))*width);
float bbHeight = (float)(Math.abs(Math.sin(angle))*width + Math.abs(Math.cos(angle))*height);
contentStream.transform(Matrix.getTranslateInstance((bbLowerLeftX + .5f*bbWidth), (bbLowerLeftY + .5f*bbHeight)));
contentStream.transform(Matrix.getRotateInstance(angle, 0, 0));
contentStream.drawImage(image, -.5f*width, -.5f*height, width, height);
}
}
PDPage page = ...;
PDRectangle mediaBox = page.getMediaBox();
float bbLowerLeftX = 50;
float bbLowerLeftY = 100;
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page) ) {
contentStream.moveTo(bbLowerLeftX, mediaBox.getLowerLeftY());
contentStream.lineTo(bbLowerLeftX, mediaBox.getUpperRightY());
contentStream.moveTo(mediaBox.getLowerLeftX(), bbLowerLeftY);
contentStream.lineTo(mediaBox.getUpperRightX(), bbLowerLeftY);
contentStream.stroke();
}
PDImageXObject image = PDImageXObject.createFromByteArray(document, IOUtils.toByteArray(resource), "Image");
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, image.getWidth(), image.getHeight(), (float)(Math.PI/4));
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .5f*image.getWidth(), .5f*image.getHeight(), 0);
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .25f*image.getWidth(), .25f*image.getHeight(), (float)(9*Math.PI/8));
通过边界框测试位置
此代码绘制与给定左下边界框坐标的左侧和底部对应的左侧和底部线条,并使用恒定的给定左下边界框角以不同的放大率和角度绘制图像
结果如下所示:
void placeImage(PDDocument document, PDPage page, PDImageXObject image, float bbLowerLeftX, float bbLowerLeftY, float width, float height, float angle) throws IOException {
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true) ) {
float bbWidth = (float)(Math.abs(Math.sin(angle))*height + Math.abs(Math.cos(angle))*width);
float bbHeight = (float)(Math.abs(Math.sin(angle))*width + Math.abs(Math.cos(angle))*height);
contentStream.transform(Matrix.getTranslateInstance((bbLowerLeftX + .5f*bbWidth), (bbLowerLeftY + .5f*bbHeight)));
contentStream.transform(Matrix.getRotateInstance(angle, 0, 0));
contentStream.drawImage(image, -.5f*width, -.5f*height, width, height);
}
}
PDPage page = ...;
PDRectangle mediaBox = page.getMediaBox();
float bbLowerLeftX = 50;
float bbLowerLeftY = 100;
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page) ) {
contentStream.moveTo(bbLowerLeftX, mediaBox.getLowerLeftY());
contentStream.lineTo(bbLowerLeftX, mediaBox.getUpperRightY());
contentStream.moveTo(mediaBox.getLowerLeftX(), bbLowerLeftY);
contentStream.lineTo(mediaBox.getUpperRightX(), bbLowerLeftY);
contentStream.stroke();
}
PDImageXObject image = PDImageXObject.createFromByteArray(document, IOUtils.toByteArray(resource), "Image");
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, image.getWidth(), image.getHeight(), (float)(Math.PI/4));
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .5f*image.getWidth(), .5f*image.getHeight(), 0);
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .25f*image.getWidth(), .25f*image.getHeight(), (float)(9*Math.PI/8));
您可以在以下答案中找到有关边界框大小计算的更多信息:
...
您可以使用以下代码正确定位图像:
void placeImage(PDDocument document, PDPage page, PDImageXObject image, float bbLowerLeftX, float bbLowerLeftY, float width, float height, float angle) throws IOException {
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true) ) {
float bbWidth = (float)(Math.abs(Math.sin(angle))*height + Math.abs(Math.cos(angle))*width);
float bbHeight = (float)(Math.abs(Math.sin(angle))*width + Math.abs(Math.cos(angle))*height);
contentStream.transform(Matrix.getTranslateInstance((bbLowerLeftX + .5f*bbWidth), (bbLowerLeftY + .5f*bbHeight)));
contentStream.transform(Matrix.getRotateInstance(angle, 0, 0));
contentStream.drawImage(image, -.5f*width, -.5f*height, width, height);
}
}
PDPage page = ...;
PDRectangle mediaBox = page.getMediaBox();
float bbLowerLeftX = 50;
float bbLowerLeftY = 100;
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page) ) {
contentStream.moveTo(bbLowerLeftX, mediaBox.getLowerLeftY());
contentStream.lineTo(bbLowerLeftX, mediaBox.getUpperRightY());
contentStream.moveTo(mediaBox.getLowerLeftX(), bbLowerLeftY);
contentStream.lineTo(mediaBox.getUpperRightX(), bbLowerLeftY);
contentStream.stroke();
}
PDImageXObject image = PDImageXObject.createFromByteArray(document, IOUtils.toByteArray(resource), "Image");
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, image.getWidth(), image.getHeight(), (float)(Math.PI/4));
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .5f*image.getWidth(), .5f*image.getHeight(), 0);
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .25f*image.getWidth(), .25f*image.getHeight(), (float)(9*Math.PI/8));
实用方法
此方法接受坐标,因为它们在PDF上下文中是有意义的,即坐标值和尺寸根据给定页面的默认用户空间坐标系y值向上递增,原点在左下角任意,但通常在左下角,边界框由左下角给定,数学中以逆时针弧度表示的角度
但是,如果需要不同的参数,可以相当容易地调整该方法。例如,如果获取边界框的左上角而不是左下角,则只需减去在方法中确定为bbHeight的边界框高度,即可计算此处使用的左下y坐标
您可以这样使用此方法:
void placeImage(PDDocument document, PDPage page, PDImageXObject image, float bbLowerLeftX, float bbLowerLeftY, float width, float height, float angle) throws IOException {
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true) ) {
float bbWidth = (float)(Math.abs(Math.sin(angle))*height + Math.abs(Math.cos(angle))*width);
float bbHeight = (float)(Math.abs(Math.sin(angle))*width + Math.abs(Math.cos(angle))*height);
contentStream.transform(Matrix.getTranslateInstance((bbLowerLeftX + .5f*bbWidth), (bbLowerLeftY + .5f*bbHeight)));
contentStream.transform(Matrix.getRotateInstance(angle, 0, 0));
contentStream.drawImage(image, -.5f*width, -.5f*height, width, height);
}
}
PDPage page = ...;
PDRectangle mediaBox = page.getMediaBox();
float bbLowerLeftX = 50;
float bbLowerLeftY = 100;
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page) ) {
contentStream.moveTo(bbLowerLeftX, mediaBox.getLowerLeftY());
contentStream.lineTo(bbLowerLeftX, mediaBox.getUpperRightY());
contentStream.moveTo(mediaBox.getLowerLeftX(), bbLowerLeftY);
contentStream.lineTo(mediaBox.getUpperRightX(), bbLowerLeftY);
contentStream.stroke();
}
PDImageXObject image = PDImageXObject.createFromByteArray(document, IOUtils.toByteArray(resource), "Image");
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, image.getWidth(), image.getHeight(), (float)(Math.PI/4));
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .5f*image.getWidth(), .5f*image.getHeight(), 0);
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .25f*image.getWidth(), .25f*image.getHeight(), (float)(9*Math.PI/8));
通过边界框测试位置
此代码绘制与给定左下边界框坐标的左侧和底部对应的左侧和底部线条,并使用恒定的给定左下边界框角以不同的放大率和角度绘制图像
结果如下所示:
void placeImage(PDDocument document, PDPage page, PDImageXObject image, float bbLowerLeftX, float bbLowerLeftY, float width, float height, float angle) throws IOException {
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true) ) {
float bbWidth = (float)(Math.abs(Math.sin(angle))*height + Math.abs(Math.cos(angle))*width);
float bbHeight = (float)(Math.abs(Math.sin(angle))*width + Math.abs(Math.cos(angle))*height);
contentStream.transform(Matrix.getTranslateInstance((bbLowerLeftX + .5f*bbWidth), (bbLowerLeftY + .5f*bbHeight)));
contentStream.transform(Matrix.getRotateInstance(angle, 0, 0));
contentStream.drawImage(image, -.5f*width, -.5f*height, width, height);
}
}
PDPage page = ...;
PDRectangle mediaBox = page.getMediaBox();
float bbLowerLeftX = 50;
float bbLowerLeftY = 100;
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page) ) {
contentStream.moveTo(bbLowerLeftX, mediaBox.getLowerLeftY());
contentStream.lineTo(bbLowerLeftX, mediaBox.getUpperRightY());
contentStream.moveTo(mediaBox.getLowerLeftX(), bbLowerLeftY);
contentStream.lineTo(mediaBox.getUpperRightX(), bbLowerLeftY);
contentStream.stroke();
}
PDImageXObject image = PDImageXObject.createFromByteArray(document, IOUtils.toByteArray(resource), "Image");
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, image.getWidth(), image.getHeight(), (float)(Math.PI/4));
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .5f*image.getWidth(), .5f*image.getHeight(), 0);
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .25f*image.getWidth(), .25f*image.getHeight(), (float)(9*Math.PI/8));
您可以在以下答案中找到有关边界框大小计算的更多信息:
...
你的代码不想要的结果是。。。?好的,我假设它没有正确定位,但是它完全关闭了吗?或者只是一点点?图像靠近所需的位置,并且具有正确的旋转。这个问题似乎与边界框有关。当用户创建设计时,输出json文件以任何旋转方式存储图像的最终边界框。我可以在大致范围内进行定位,但是因为在用户开始旋转图像之前,我们没有原始的边界框,所以我们无法重建他们在PDF上定位图像时所采取的过程。但是您的数据所指的边界框与往常一样是最小的,不是吗?在这种情况下,确定所有数据应该是简单的数学。如何确定调整后的YPO?是的,最小值是正确的。好吧,如果我能访问图像的四个角位置,计算起来会很容易。但就我所知,我没有办法这么做?除非我忽略了什么。adjustedYPos=page.getMediaBox.getHeight-element.getTop+ScaleHeights我的答案有帮助吗?代码的不需要的结果是。。。?好的,我假设它没有正确定位,但是它完全关闭了吗?或者只是一点点?图像靠近所需的位置,并且具有正确的旋转。这个问题似乎与边界框有关。当用户创建设计时,输出json文件以任何旋转方式存储图像的最终边界框。我可以在大致范围内进行定位,但是因为在用户开始旋转图像之前,我们没有原始的边界框,所以我们无法重建他们在PDF上定位图像时所采取的过程。但是您的数据所指的边界框与往常一样是最小的,不是吗?在这种情况下,确定所有数据应该是简单的数学。如何确定调整后的YPO?是的,最小值是正确的。
好吧,如果我能访问图像的四个角位置,计算起来会很容易。但就我所知,我没有办法这么做?除非我忽略了什么。adjustedYPos=page.getMediaBox.getHeight-element.getTop+ScaleHeights我的答案有帮助吗?嘿,mkl。我今天看了这个,抱歉花了点时间。事实证明,我所指的位置数据实际上也不是左上角的边界框,而是左上角的旋转图像。这使事情比预期的容易。我能够稍微修改提供的实现,现在一切都按预期工作。我会把你的答案标记为正确的,因为它回答了我最初的问题,但也只需要对数据做一些小的修改,因为它实际上结束了;嘿,mkl。我今天看了这个,抱歉花了点时间。事实证明,我所指的位置数据实际上也不是左上角的边界框,而是左上角的旋转图像。这使事情比预期的容易。我能够稍微修改提供的实现,现在一切都按预期工作。我会把你的答案标记为正确的,因为它回答了我最初的问题,但也只需要对数据做一些小的修改,因为它实际上结束了;