spring 映射中的 PNG 生成图像不适用于 Apache FOP 生成的 PDF
PNG generated image in spring mapping not working on apache FOP generated PDF
首先,这不是这样的 link
Apache FOP in a Java Applet - No ImagePreloader found for data
因为除了由 Spring 映射动态生成的图像外,所有图像(包括 PNG)都正常显示。
所以,也就是说,我有以下情况。我有一个带有此映射的控制器:
@GetMapping(value = {
"/static/test/qr.png"
}, produces = MediaType.IMAGE_PNG_VALUE)
public void genericQR(HttpServletRequest request, HttpServletResponse response) throws WriterException, IOException {
response.setContentType("image/png");
final byte[] bytes = new QrCodeGenerator().generate("HELLO", null);
response.setContentLength(bytes.length);
response.getOutputStream().write(bytes);
}
二维码生成器class是这样的:
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author jpaoletti
*/
public class QrCodeGenerator {
private final int width;
private final int height;
public QrCodeGenerator() {
width = 400;
height = 400;
}
public QrCodeGenerator(int width, int height) {
this.width = width;
this.height = height;
}
public byte[] generate(String content, String logo) throws WriterException, IOException {
// Create new configuration that specifies the error correction
Map<EncodeHintType, ErrorCorrectionLevel> hints = new HashMap<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
QRCodeWriter writer = new QRCodeWriter();
BitMatrix bitMatrix = null;
ByteArrayOutputStream os = new ByteArrayOutputStream();
// Create a qr code with the url as content and a size of WxH px
bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
// Load QR image
BufferedImage qrImage = MatrixToImageWriter.toBufferedImage(bitMatrix, getMatrixConfig());
// Load logo image
BufferedImage overly = logo == null ? null : getOverly(logo);
// Calculate the delta height and width between QR code and logo
int deltaHeight = overly == null ? null : (qrImage.getHeight() - overly.getHeight());
int deltaWidth = overly == null ? null : (qrImage.getWidth() - overly.getWidth());
// Initialize combined image
BufferedImage combined = new BufferedImage(qrImage.getHeight(), qrImage.getWidth(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) combined.getGraphics();
// Write QR code to new image at position 0/0
g.drawImage(qrImage, 0, 0, null);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));
if (overly != null) {
g.drawImage(overly, (int) Math.round(deltaWidth / 2), (int) Math.round(deltaHeight / 2), null);
}
ImageIO.write(combined, "png", os);
return os.toByteArray();
}
private BufferedImage getOverly(String LOGO) throws IOException {
URL url = new URL(LOGO);
return ImageIO.read(url);
}
private MatrixToImageConfig getMatrixConfig() {
// ARGB Colors
// Check Colors ENUM
return new MatrixToImageConfig(QrCodeGenerator.Colors.BLACK.getArgb(), QrCodeGenerator.Colors.WHITE.getArgb());
}
public enum Colors {
BLUE(0xFF40BAD0),
RED(0xFFE91C43),
PURPLE(0xFF8A4F9E),
ORANGE(0xFFF4B13D),
WHITE(0xFFFFFFFF),
BLACK(0xFF000000);
private final int argb;
Colors(final int argb) {
this.argb = argb;
}
public int getArgb() {
return argb;
}
}
}
从网站或浏览器直接访问显示图像很好,但试图将其包含在 apache fop 生成的 pdf 中会引发以下错误:
2021/09/29 09:08:47 [http-nio-8084-exec-73] ERROR org.apache.fop.apps.FOUserAgent - Image not available. URI: http://localhost:8084/static/test/qr.png. Reason: org.apache.xmlgraphics.image.loader.ImageException: The file format is not supported. No ImagePreloader found for http://localhost:8084/static/test/qr.png (No context info available)
org.apache.xmlgraphics.image.loader.ImageException: The file format is not supported. No ImagePreloader found for http://localhost:8084/static/test/qr.png
at org.apache.xmlgraphics.image.loader.ImageManager.preloadImage(ImageManager.java:181)
at org.apache.xmlgraphics.image.loader.cache.ImageCache.needImageInfo(ImageCache.java:127)
at org.apache.xmlgraphics.image.loader.ImageManager.getImageInfo(ImageManager.java:123)
我尝试了很多选择,甚至换成JPG 也有同样的结果。有什么想法吗?
这行得通
<fo:block>
<fo:external-graphic src="url('{$url-base}/static/img/logosite.png')" content-height="scale-to-fit" height="1cm" />
</fo:block>
这行不通
<fo:block font-size="10pt" margin-top="0cm">
<fo:external-graphic src="url('{$url-base}/static/test/qr.png')" content-height="scale-to-fit" height="3cm" content-width="3cm" scaling="non-uniform" />
</fo:block>
提前致谢
原来是安全问题。我可以从浏览器访问,但只是因为我已登录。如果我尝试在未登录的情况下获取图像,则会弹出安全错误。
所以解决方案是使用控制器模式和 security:http 拦截-url
首先,这不是这样的 link
Apache FOP in a Java Applet - No ImagePreloader found for data
因为除了由 Spring 映射动态生成的图像外,所有图像(包括 PNG)都正常显示。
所以,也就是说,我有以下情况。我有一个带有此映射的控制器:
@GetMapping(value = {
"/static/test/qr.png"
}, produces = MediaType.IMAGE_PNG_VALUE)
public void genericQR(HttpServletRequest request, HttpServletResponse response) throws WriterException, IOException {
response.setContentType("image/png");
final byte[] bytes = new QrCodeGenerator().generate("HELLO", null);
response.setContentLength(bytes.length);
response.getOutputStream().write(bytes);
}
二维码生成器class是这样的:
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author jpaoletti
*/
public class QrCodeGenerator {
private final int width;
private final int height;
public QrCodeGenerator() {
width = 400;
height = 400;
}
public QrCodeGenerator(int width, int height) {
this.width = width;
this.height = height;
}
public byte[] generate(String content, String logo) throws WriterException, IOException {
// Create new configuration that specifies the error correction
Map<EncodeHintType, ErrorCorrectionLevel> hints = new HashMap<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
QRCodeWriter writer = new QRCodeWriter();
BitMatrix bitMatrix = null;
ByteArrayOutputStream os = new ByteArrayOutputStream();
// Create a qr code with the url as content and a size of WxH px
bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
// Load QR image
BufferedImage qrImage = MatrixToImageWriter.toBufferedImage(bitMatrix, getMatrixConfig());
// Load logo image
BufferedImage overly = logo == null ? null : getOverly(logo);
// Calculate the delta height and width between QR code and logo
int deltaHeight = overly == null ? null : (qrImage.getHeight() - overly.getHeight());
int deltaWidth = overly == null ? null : (qrImage.getWidth() - overly.getWidth());
// Initialize combined image
BufferedImage combined = new BufferedImage(qrImage.getHeight(), qrImage.getWidth(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) combined.getGraphics();
// Write QR code to new image at position 0/0
g.drawImage(qrImage, 0, 0, null);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));
if (overly != null) {
g.drawImage(overly, (int) Math.round(deltaWidth / 2), (int) Math.round(deltaHeight / 2), null);
}
ImageIO.write(combined, "png", os);
return os.toByteArray();
}
private BufferedImage getOverly(String LOGO) throws IOException {
URL url = new URL(LOGO);
return ImageIO.read(url);
}
private MatrixToImageConfig getMatrixConfig() {
// ARGB Colors
// Check Colors ENUM
return new MatrixToImageConfig(QrCodeGenerator.Colors.BLACK.getArgb(), QrCodeGenerator.Colors.WHITE.getArgb());
}
public enum Colors {
BLUE(0xFF40BAD0),
RED(0xFFE91C43),
PURPLE(0xFF8A4F9E),
ORANGE(0xFFF4B13D),
WHITE(0xFFFFFFFF),
BLACK(0xFF000000);
private final int argb;
Colors(final int argb) {
this.argb = argb;
}
public int getArgb() {
return argb;
}
}
}
从网站或浏览器直接访问显示图像很好,但试图将其包含在 apache fop 生成的 pdf 中会引发以下错误:
2021/09/29 09:08:47 [http-nio-8084-exec-73] ERROR org.apache.fop.apps.FOUserAgent - Image not available. URI: http://localhost:8084/static/test/qr.png. Reason: org.apache.xmlgraphics.image.loader.ImageException: The file format is not supported. No ImagePreloader found for http://localhost:8084/static/test/qr.png (No context info available)
org.apache.xmlgraphics.image.loader.ImageException: The file format is not supported. No ImagePreloader found for http://localhost:8084/static/test/qr.png
at org.apache.xmlgraphics.image.loader.ImageManager.preloadImage(ImageManager.java:181)
at org.apache.xmlgraphics.image.loader.cache.ImageCache.needImageInfo(ImageCache.java:127)
at org.apache.xmlgraphics.image.loader.ImageManager.getImageInfo(ImageManager.java:123)
我尝试了很多选择,甚至换成JPG 也有同样的结果。有什么想法吗?
这行得通
<fo:block>
<fo:external-graphic src="url('{$url-base}/static/img/logosite.png')" content-height="scale-to-fit" height="1cm" />
</fo:block>
这行不通
<fo:block font-size="10pt" margin-top="0cm">
<fo:external-graphic src="url('{$url-base}/static/test/qr.png')" content-height="scale-to-fit" height="3cm" content-width="3cm" scaling="non-uniform" />
</fo:block>
提前致谢
原来是安全问题。我可以从浏览器访问,但只是因为我已登录。如果我尝试在未登录的情况下获取图像,则会弹出安全错误。
所以解决方案是使用控制器模式和 security:http 拦截-url