Spring Boot convert (load image from jsp) to (load from html) - java

I got an old project which is using Strut1 framework. So it uses JSP to load captcha image from another JSP file. Source code below.
Now, I upgrade that project using Spring Boot and Thymeleaf layout. I don't know how to convert it into html. Please take a look and give ideas.
Thanks.
For login.jsp
<div id="captcha" style="cursor: pointer; height: 30px; width: 150px; display: inline-block; float: left"><img src="captcha.jsp"></div>
captcha.jsp
<%# page contentType="text/html;charset=UTF-8"%>
<%# page import="java.util.*"%>
<%# page import="java.io.*"%>
<%# page import="javax.servlet.*"%>
<%# page import="javax.servlet.http.*"%>
<%# page import="java.awt.*"%>
<%# page import="java.awt.image.*"%>
<%# page import="javax.imageio.*"%>
<%# page import="java.awt.geom.*"%>
<%# page import="vn.com.tivn.online.acquiring.util.ValueUtil"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>captcha</title>
</head>
<body>
<%
//========================================================
// Kick Ass Captcha JSP
//
// Michael Connor 2007
//
// I just couldn't handle the thought of downloading a
// big jar and configuring some servlet.xml and having
// little to no control of anything...
// You can send in height and width parameters.
// The captcha value will be placed in the session in
// a parameter called 'captcha'
//
// Feel free to use this code and do whatever the hell
// you want to it.
//========================================================
String imageFormat = "png";
response.setContentType("image/" + imageFormat);
try {
// you can pass in fontSize, width, height via the request
Color backgroundColor = Color.blue;
Color borderColor = Color.black;
Color textColor = Color.white;
Color circleColor = new Color(160,160,160);
Font textFont = new Font("Arial", Font.PLAIN, paramInt(request, "fontSize", 24));
int charsToPrint = 6;
int width = paramInt(request, "width", 150);
int height = paramInt(request, "height", 30);
int circlesToDraw = 6;
float horizMargin = 20.0f;
float imageQuality = 0.95f; // max is 1.0 (this is for jpeg)
double rotationRange = 0.7; // this is radians
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) bufferedImage.getGraphics();
g.setColor(backgroundColor);
g.fillRect(0, 0, width, height);
// lets make some noisey circles
g.setColor(circleColor);
for ( int i = 0; i < circlesToDraw; i++ ) {
int circleRadius = (int) (Math.random() * height / 2.0);
int circleX = (int) (Math.random() * width - circleRadius);
int circleY = (int) (Math.random() * height - circleRadius);
g.drawOval(circleX, circleY, circleRadius * 2, circleRadius * 2);
}
g.setColor(textColor);
g.setFont(textFont);
FontMetrics fontMetrics = g.getFontMetrics();
int maxAdvance = fontMetrics.getMaxAdvance();
int fontHeight = fontMetrics.getHeight();
// i removed 1 and l and i because there are confusing to users...
// Z, z, and N also get confusing when rotated
// 0, O, and o are also confusing...
// lowercase G looks a lot like a 9 so i killed it
// this should ideally be done for every language...
// i like controlling the characters though because it helps prevent confusion
String elegibleChars = "ABCDEFGHJKLMPQRSTUVWXYabcdefhjkmnpqrstuvwxy23456789";
char[] chars = elegibleChars.toCharArray();
float spaceForLetters = -horizMargin * 2 + width;
float spacePerChar = spaceForLetters / (charsToPrint - 1.0f);
AffineTransform transform = g.getTransform();
StringBuffer finalString = new StringBuffer();
for ( int i = 0; i < charsToPrint; i++ ) {
double randomValue = Math.random();
int randomIndex = (int) Math.round(randomValue * (chars.length - 1));
char characterToShow = chars[randomIndex];
finalString.append(characterToShow);
// this is a separate canvas used for the character so that
// we can rotate it independently
int charImageWidth = maxAdvance * 2;
int charImageHeight = fontHeight * 2;
int charWidth = fontMetrics.charWidth(characterToShow);
int charDim = Math.max(maxAdvance, fontHeight);
int halfCharDim = (int) (charDim / 2);
BufferedImage charImage = new BufferedImage(charDim, charDim, BufferedImage.TYPE_INT_ARGB);
Graphics2D charGraphics = charImage.createGraphics();
charGraphics.translate(halfCharDim, halfCharDim);
double angle = (Math.random() - 0.5) * rotationRange;
charGraphics.transform(AffineTransform.getRotateInstance(angle));
charGraphics.translate(-halfCharDim,-halfCharDim);
charGraphics.setColor(textColor);
charGraphics.setFont(textFont);
int charX = (int) (0.5 * charDim - 0.5 * charWidth);
charGraphics.drawString("" + characterToShow, charX,
(int) ((charDim - fontMetrics.getAscent())
/ 2 + fontMetrics.getAscent()));
float x = horizMargin + spacePerChar * (i) - charDim / 2.0f;
int y = (int) ((height - charDim) / 2);
//System.out.println("x=" + x + " height=" + height + " charDim=" + charDim + " y=" + y + " advance=" + maxAdvance + " fontHeight=" + fontHeight + " ascent=" + fontMetrics.getAscent());
g.drawImage(charImage, (int) x, y, charDim, charDim, null, null);
charGraphics.dispose();
}
// let's do the border
g.setColor(borderColor);
g.drawRect(0, 0, width - 1, height - 1);
//Write the image as a jpg
Iterator iter = ImageIO.getImageWritersByFormatName(imageFormat);
if( iter.hasNext() ) {
ImageWriter writer = (ImageWriter)iter.next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
if ( imageFormat.equalsIgnoreCase("jpg") || imageFormat.equalsIgnoreCase("jpeg") ) {
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(imageQuality);
}
writer.setOutput(ImageIO.createImageOutputStream(response.getOutputStream()));
IIOImage imageIO = new IIOImage(bufferedImage, null, null);
writer.write(null, imageIO, iwp);
} else {
throw new RuntimeException("no encoder found for jsp");
}
// let's stick the final string in the session
request.getSession().setAttribute("wirecardmposcaptcha", finalString.toString());
System.out.print("----------"+g.dispose());
g.dispose();
} catch (IOException ioe) {
throw new RuntimeException("Unable to build image" , ioe);
}
%>
<%!
public static String paramString(HttpServletRequest request, String paramName, String defaultString) {
return request.getParameter(paramName) != null ? request.getParameter(paramName) : defaultString;
}
public static int paramInt(HttpServletRequest request, String paramName, int defaultInt) {
return request.getParameter(paramName) != null ? Integer.parseInt(request.getParameter(paramName)) : defaultInt;
}
%>
<%
if(ValueUtil.SUPPORT_SSL){
String sessionid = request.getSession().getId();
response.addHeader("SET-COOKIE", "JSESSIONID=" + sessionid + "; Secure; HttpOnly");
}
%>
</body>
</html>

As an inital approach:
Create a file under resources/templates folder called login.html and place the same code as in login.jsp. Replace <img src="captcha.jsp"> by something like <img th:src="${capchaUrl}"> If this is not an entire page you can also create a fragment and include it wherever you need.
In your template controller add the methods needed to create the captcha by refactoring captcha.jsp and, once you have the captcha, you can add it to the model like model.addAttribute("capchaUrl", the_generated_captcha); it should be populated in the template.

Related

How to add a text above a previous added image and center it above this image with pdfbox?

My aim is to add a image to a pdf and write a text above this image. I have centered the image and the text should be center above the image with a little margin to the image.
Currently the image will be added and centered but the text is not centered.
Here my current code. The interesting part is where the method drawTitleAtTop will be called. Here i have added the height of the newly added image to the y postion plus a margin of 3. The x coordinate I calculate depending on the incoming text but there is some miscalculation. Any advice?
private static void addScaledImage(ImageData imgData, PDDocument pdDocument, Dimension thePdfDimension) {
ImageHelper helper = Scalr::resize;
byte[] scaledImage = ImageUtils.resizeImageKeepAspectRatio(helper, imgData.getImageBinary(), thePdfDimension.width);
PDRectangle rectangle = pdDocument.getPage(0).getMediaBox();
PDPage page = new PDPage(rectangle);
pdDocument.addPage(page);
PDImageXObject pdImage = null;
try {
pdImage = PDImageXObject.createFromByteArray(pdDocument, scaledImage, null);
LOG.debug("size of scaled image is x: {0} y {1}", pdImage.getWidth(), pdImage.getHeight());
int xForImage = (thePdfDimension.width - pdImage.getWidth()) / 2 ;
int yForImage = (thePdfDimension.height - pdImage.getHeight()) / 2;
LOG.debug("new x {0} new y {1}", xForImage, yForImage);
try (PDPageContentStream contentStream = new PDPageContentStream(pdDocument, page, AppendMode.APPEND, true, true)) {
if (StringUtils.isNotBlank(imgData.getTitle())) {
yForImage = xForImage - 20;
contentStream.drawImage(pdImage, xForImage, yForImage, pdImage.getWidth(), pdImage.getHeight());
drawTitelAtTop(imgData, page, xForImage , yForImage + pdImage.getHeight() + 3, contentStream);
} else {
contentStream.drawImage(pdImage, xForImage, yForImage, pdImage.getWidth(), pdImage.getHeight());
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void drawTitelAtTop(ImageData imgData, PDPage page, int x, int y, PDPageContentStream contentStream) throws IOException {
PDFont font = PDType1Font.COURIER;
int fontSize = FONT_SIZE_FOR_TITLE;
float titleWidth = font.getStringWidth(imgData.getTitle()) / 1000 * fontSize;
LOG.debug("title width is " + titleWidth);
contentStream.setFont(font, fontSize);
contentStream.beginText();
float tx = ((x - titleWidth) / 2) + x;
//float tx = x;
//float ty = page.getMediaBox().getHeight() - marginTop + (marginTop / 4);
float ty = y;
LOG.debug("title offset x {0} y {1}", tx, ty);
contentStream.newLineAtOffset(tx,
ty);
contentStream.showText(imgData.getTitle());
contentStream.endText();
}

PDAnnotationTextMarkup missing when rendering a pdf page to image PDFBox Java

I have code written using PDFBox API that highlights the words in a PDF but when I convert highlighted PDF pages to images, then whatever I have highlighted gets disappeared from the image.
Below screenshot is with highlighted text, for highlighting I have used PDFBox's PDAnnotationTextMarkup class:
Highlighted PDF Page
Below is the image after converting the pdf page to image:
Highlighted PDF Page Image after converting
Below is the code I have used for converting PDF to Image:
PDDocument document = PDDocument.load(new File(pdfFilename));
PDFRenderer pdfRenderer = new PDFRenderer(document);
int pageCounter = 0;
for (PDPage page : document.getPages())
{
BufferedImage bim = pdfRenderer.renderImageWithDPI(pageCounter, 300, ImageType.RGB);
ImageIOUtil.writeImage(bim, pdfFilename + "-" + (pageCounter++) + ".png", 300);
}
document.close();
Please suggest what is wrong here, why PDFRenderer not able to take PDF page image along with the highlighted red box.
Below is the code I used to highlight the text in PDF:
private void highlightText(String pdfFilePath, String highlightedPdfFilePath) {
try {
// Loading an existing document
File file = new File(highlightedPdfFilePath);
if (!file.exists()) {
file = new File(pdfFilePath);
}
PDDocument document = PDDocument.load(file);
// extended PDFTextStripper class
PDFTextStripper stripper = new PDFTextHighlighter();
// Get number of pages
int number_of_pages = document.getDocumentCatalog().getPages().getCount();
// The method writeText will invoke an override version of
// writeString
Writer dummy = new OutputStreamWriter(new ByteArrayOutputStream());
stripper.writeText(document, dummy);
// Print collected information
System.out.println("tokenStream:::"+tokenStream);
System.out.println("tokenStream size::"+tokenStream.size());
System.out.println("coordinates size::"+coordinates.size());
double page_height;
double page_width;
double width, height, minx, maxx, miny, maxy;
int rotation;
// scan each page and highlitht all the words inside them
for (int page_index = 0; page_index < number_of_pages; page_index++) {
// get current page
PDPage page = document.getPage(page_index);
// Get annotations for the selected page
List<PDAnnotation> annotations = page.getAnnotations();
// Define a color to use for highlighting text
PDColor red = new PDColor(new float[] { 1, 0, 0 }, PDDeviceRGB.INSTANCE);
// Page height and width
page_height = page.getMediaBox().getHeight();
page_width = page.getMediaBox().getWidth();
// Scan collected coordinates
for (int i = 0; i < coordinates.size(); i++) {
if (!differencePgaeNumber.contains(page_index)) {
differencePgaeNumber.add(page_index);
}
// if the current coordinates are not related to the current
// page, ignore them
if ((int) coordinates.get(i)[4] != (page_index + 1))
continue;
else {
// get rotation of the page...portrait..landscape..
rotation = (int) coordinates.get(i)[7];
// page rotated of 90degrees
if (rotation == 90) {
height = coordinates.get(i)[5];
width = coordinates.get(i)[6];
width = (page_height * width) / page_width;
// define coordinates of a rectangle
maxx = coordinates.get(i)[1];
minx = coordinates.get(i)[1] - height;
miny = coordinates.get(i)[0];
maxy = coordinates.get(i)[0] + width;
} else // i should add here the cases -90/-180 degrees
{
height = coordinates.get(i)[5];
minx = coordinates.get(i)[0];
maxx = coordinates.get(i)[2];
miny = page_height - coordinates.get(i)[1];
maxy = page_height - coordinates.get(i)[3] + height;
}
// Add an annotation for each scanned word
PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(
PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
txtMark.setColor(red);
txtMark.setConstantOpacity((float) 0.3); // 30%
// transparent
PDRectangle position = new PDRectangle();
position.setLowerLeftX((float) minx);
position.setLowerLeftY((float) miny);
position.setUpperRightX((float) maxx);
position.setUpperRightY((float) ((float) maxy + height));
txtMark.setRectangle(position);
float[] quads = new float[8];
quads[0] = position.getLowerLeftX(); // x1
quads[1] = position.getUpperRightY() - 2; // y1
quads[2] = position.getUpperRightX(); // x2
quads[3] = quads[1]; // y2
quads[4] = quads[0]; // x3
quads[5] = position.getLowerLeftY() - 2; // y3
quads[6] = quads[2]; // x4
quads[7] = quads[5]; // y5
txtMark.setQuadPoints(quads);
txtMark.setContents(tokenStream.get(i).toString());
annotations.add(txtMark);
}
}
}
// Saving the document in a new file
File highlighted_doc = new File(highlightedPdfFilePath);
document.save(highlighted_doc);
document.close();
} catch (IOException e) {
System.out.println(e);
}
}
You need to construct the visual appearance of the annotation with this call:
txtMark.constructAppearances(document);

Not detecting height and width change for applet run via window.open()

I created a clock applet that resizes the text as the user stretches the window around. In Netbeans it works fine but running the jar on the web server it does not detect any changes in size. I initially was using getWidth() and getHeight() in the paint function to get the current window size. When I realized it wasn't detecting changes outside of Netbeans I switched/add a componentResized() listener but that also doesn't detect any resizing outside of Netbeans either.
On the web server index.html page I am using win=window.open(url, name, the_size) to open a window with the clock applet inside. Why is the listener not seeing any resizing as I stretch the window around? Is it because window.open() window is different from the Netbean pop up window somehow?
#Override
public void init() {
if (getParameter("verbose") != null)
{
try {
m_verboseLevel = Integer.parseInt(getParameter("verbose"));
} catch (NumberFormatException e) {
System.out.println(Thread.currentThread().getName() + " verbose: " + getParameter("verbose") + " is not 0->3");
m_verboseLevel = 0;
}
}
m_size = getParameter("size");
m_clock_color = getParameter("color");
// Add listener to update width and height as user changes it
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
m_w = getWidth();
m_h = getHeight();
System.out.println(m_w + " " + m_h);
}
});
try {
In paint the m_w and m_h are initially 0 since since nothing has moved. I call getWidth() and getHeight() and the output matches the html applet width and height values 600 and 800. But outside of Netbeans m_h/m_w never changes so the scale logic doesn't change anything.
#Override
public void paint(Graphics g) {
// first time?
if ((m_w == 0) && (m_h == 0)) {
m_w = getWidth(); // return the width of the applet
m_h = getHeight(); // return the height of the applet
}
// Use buffering for smooth update
BufferedImage bi = new BufferedImage(m_w, m_h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
super.paint(g2d);
String[] lines = new String[2];
lines[0] = "Acquisition of Signal";
lines[1] = "Loss of Signal";
// first time?
if (m_clockLine == 0) {
FontRenderContext frc = g2d.getFontRenderContext();
LineMetrics metrics = m_clock_font.getLineMetrics(lines[1], frc);
// Omitt the descent from the height variable.
String time = "00:00:00";
g2d.setFont(m_clock_font);
float height1 = metrics.getAscent() + metrics.getDescent();
m_width = m_clock_font.getStringBounds(time, frc).getWidth();
m_clockLine = (int) (metrics.getAscent() - 1);
metrics = m_label_font.getLineMetrics(lines[0], frc);
float height2 = metrics.getAscent() + metrics.getDescent();
m_labelLine = (int) (metrics.getAscent() - 1);
metrics = m_tk_font.getLineMetrics(lines[1], frc);
float height3 = metrics.getAscent() + metrics.getDescent();
m_titleLine = (int) (metrics.getAscent() - 1);
m_width += 22*2;
m_height = height1 + height2 + height3 + height1 + height2 + (m_padding*4);
}
System.out.println(m_w + " " + m_width + " " + m_h + " " + m_height);
g2d.scale(m_w/m_width, m_h/m_height);
/* Make background black */
g2d.setColor(Color.black);
g2d.fillRect(0, 0, (int)m_width, (int)m_height);
/* Draw individual clock labels */
g2d.setFont(m_label_font);
g2d.setColor(m_main_color);
g2d.drawString(lines[0], 145, m_clockLine+m_labelLine+m_padding);
g2d.drawString(lines[1], 220, m_clockLine+m_labelLine+m_titleLine+m_clockLine+m_labelLine+(m_padding*4));
// Write check clock timer lines
if (m_c != null) {
m_c.print(g2d, m_labelLine, m_clockLine, m_titleLine, m_padding, m_width, m_height);
}
g2d.dispose();
g.drawImage(bi, 0, 0, this);
} // end paint
Ok, after a lot of googling I found out what the problem is. When the applet is checking it's dimensions either using the addComponentListener componentResized or the getWidth/getHeight call it is reading the html width and height values for the applet/object. When using the Netbeans Applet Viewer these values are being changed as the viewer is being stretched. But in a html page the width and height are not changing as the browser is resized. This is why the applet size doesn't change when you stretch the browser. So the solution in the real environment is reset the width and height values via javascript so that the applet can see the new dimensions onLoad. Note: onResize doesn't seem to ever go off but I left it in anyway.
So I removed the componentResized logic and in the paint function just call getWidth/getHeight for the applet dimensions. This is the final paint function.
#Override
public void paint(Graphics g) {
// This makes the applet resizable
int w = getWidth(); // return the width of the applet
int h = getHeight(); // return the height of the applet
// Use buffering for smooth update
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
super.paint(g2d);
String[] lines = new String[2];
lines[0] = "Acquisition of Signal";
lines[1] = "Loss of Signal";
// first time?
if (m_clockLine == 0) {
FontRenderContext frc = g2d.getFontRenderContext();
LineMetrics metrics = m_clock_font.getLineMetrics(lines[1], frc);
// Omitt the descent from the height variable.
String time = "00:00:00";
g2d.setFont(m_clock_font);
float height1 = metrics.getAscent() + metrics.getDescent();
m_width = m_clock_font.getStringBounds(time, frc).getWidth();
m_clockLine = (int) (metrics.getAscent() - 1);
metrics = m_label_font.getLineMetrics(lines[0], frc);
float height2 = metrics.getAscent() + metrics.getDescent();
m_labelLine = (int) (metrics.getAscent() - 1);
metrics = m_tk_font.getLineMetrics(lines[1], frc);
float height3 = metrics.getAscent() + metrics.getDescent();
m_titleLine = (int) (metrics.getAscent() - 1);
m_width += 22*2;
m_height = height1 + height2 + height3 + height1 + height2 + (m_padding*4);
}
g2d.scale(w/m_width, h/m_height);
/* Make background black */
g2d.setColor(Color.black);
g2d.fillRect(0, 0, (int)m_width, (int)m_height);
/* Draw individual clock labels */
g2d.setFont(m_label_font);
g2d.setColor(m_main_color);
g2d.drawString(lines[0], 145, m_clockLine+m_labelLine+m_padding);
g2d.drawString(lines[1], 220, m_clockLine+m_labelLine+m_titleLine+m_clockLine+m_labelLine+(m_padding*4));
// Write check clock timer line
if (m_c != null) {
m_c.print(g2d, m_labelLine, m_clockLine, m_titleLine, m_padding, m_width, m_height);
}
g2d.dispose();
g.drawImage(bi, 0, 0, this);
} // end paint
In the html script I added the following logic:
<html>
<head>
<TITLE>Terra Small Clock</TITLE>
<meta content="text/html; charset=utf-8" http-equiv="content-type">
<meta content="IE=5.0000" http-equiv="X-UA-Compatible">
<meta name="GENERATOR" content="MSHTML 11.00.9600.17842">
</head>
<SCRIPT LANGUAGE="JavaScript">
/*
Description:
The re-size function job is to reset the applet width and height to the new dimensions as the
user stretches the browser window. The clock applet will then use the "current" width and
height to scale the clock.
*/
function resize()
{
if (navigator.appName.indexOf("Microsoft") != -1)
{
// 100% works fine on object tag with IE
return;
}
var w_newWidth,w_newHeight;
var netscapeScrollWidth=0;
w_newWidth = window.innerWidth-netscapeScrollWidth;
w_newHeight = window.innerHeight-netscapeScrollWidth;
var appletDiv = document.getElementById('clockApp');
if (appletDiv != null) {
appletDiv.style.width = w_newWidth + "px";
appletDiv.style.height = w_newHeight + "px";
}
}
window.onResize = resize;
window.onLoad = resize;
</SCRIPT>
<body bgcolor="000000" leftmargin="0" rightmargin="0" topmargin="0" marginheight="0" marginwidth="0" onResize="resize()" onLoad="resize()">
<p style="text-align:center">
<object type="application/x-java-applet" id="clockApp" width="240" height="230">
<param name="codebase" value="https://<host stuff>.nasa.gov/java_clocks/classes/" />
<param name="code" value="aosClock.class" />
<param name="archive" value="clock.jar" />
<param name="verbose" value="0" />
<param name="color" value="green" />
<param name="input_file" value="https://<host stuff>.nasa.gov/java_clocks/terra/terra_aos_times" />
</object>
</p>
</body>
</html>
So when I stop stretching the browser window the onLoad goes off and the applet/object width and height are reset. The applet then scales the clock for the new dimensions.

How to get current Session value of Captcha?

Please help me anyone! I'm stuck!
I'm trying to compare value inserted in textfield and value shown in Captcha (image), if they match it will show alert('Yes!') otherwise alert('No!'). But when I trying to get session value of Captcha (request.getSession().getAttribute("captcha")) it gets previous value of it!
How to make sure that value of Catcha if the same as user sees on image?
Captcha.jsp:
<%# page import="java.util.*"%>
<%# page import="java.io.*"%>
<%# page import="javax.servlet.*"%>
<%# page import="javax.servlet.http.*"%>
<%# page import="java.awt.*"%>
<%# page import="java.awt.image.*"%>
<%# page import="javax.imageio.*"%>
<%# page import="java.awt.geom.*"%>
<%
String imageFormat = "jpg";
response.setContentType("image/" + imageFormat);
try {
// you can pass in fontSize, width, height via the request
Color backgroundColor = Color.red;
Color borderColor = Color.black;
Color textColor = Color.white;
Color circleColor = new Color(160, 160, 160);
Font textFont = new Font("Arial", Font.PLAIN, paramInt(request,
"fontSize", 24));
int charsToPrint = 6;
int width = paramInt(request, "width", 150);
int height = paramInt(request, "height", 80);
int circlesToDraw = 6;
float horizMargin = 20.0f;
float imageQuality = 0.95f; // max is 1.0 (this is for jpeg)
double rotationRange = 0.7; // this is radians
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) bufferedImage.getGraphics();
g.setColor(backgroundColor);
g.fillRect(0, 0, width, height);
// lets make some noisey circles
g.setColor(circleColor);
for (int i = 0; i < circlesToDraw; i++) {
int circleRadius = (int) (Math.random() * height / 2.0);
int circleX = (int) (Math.random() * width - circleRadius);
int circleY = (int) (Math.random() * height - circleRadius);
g.drawOval(circleX, circleY, circleRadius * 2,
circleRadius * 2);
}
g.setColor(textColor);
g.setFont(textFont);
FontMetrics fontMetrics = g.getFontMetrics();
int maxAdvance = fontMetrics.getMaxAdvance();
int fontHeight = fontMetrics.getHeight();
// i removed 1 and l and i because there are confusing to users...
// Z, z, and N also get confusing when rotated
// 0, O, and o are also confusing...
// lowercase G looks a lot like a 9 so i killed it
// this should ideally be done for every language...
// i like controlling the characters though because it helps prevent confusion
String elegibleChars = "ABCDEFGHJKLMPQRSTUVWXYabcdefhjkmnpqrstuvwxy23456789";
char[] chars = elegibleChars.toCharArray();
float spaceForLetters = -horizMargin * 2 + width;
float spacePerChar = spaceForLetters / (charsToPrint - 1.0f);
AffineTransform transform = g.getTransform();
StringBuffer finalString = new StringBuffer();
for (int i = 0; i < charsToPrint; i++) {
double randomValue = Math.random();
int randomIndex = (int) Math.round(randomValue * (chars.length - 1));
char characterToShow = chars[randomIndex];
finalString.append(characterToShow);
// this is a separate canvas used for the character so that
// we can rotate it independently
int charImageWidth = maxAdvance * 2;
int charImageHeight = fontHeight * 2;
int charWidth = fontMetrics.charWidth(characterToShow);
int charDim = Math.max(maxAdvance, fontHeight);
int halfCharDim = (int) (charDim / 2);
BufferedImage charImage = new BufferedImage(charDim,
charDim, BufferedImage.TYPE_INT_ARGB);
Graphics2D charGraphics = charImage.createGraphics();
charGraphics.translate(halfCharDim, halfCharDim);
double angle = (Math.random() - 0.5) * rotationRange;
charGraphics.transform(AffineTransform
.getRotateInstance(angle));
charGraphics.translate(-halfCharDim, -halfCharDim);
charGraphics.setColor(textColor);
charGraphics.setFont(textFont);
int charX = (int) (0.5 * charDim - 0.5 * charWidth);
charGraphics
.drawString(
"" + characterToShow,
charX,
(int) ((charDim - fontMetrics.getAscent()) / 2 + fontMetrics
.getAscent()));
float x = horizMargin + spacePerChar * (i) - charDim / 2.0f;
int y = (int) ((height - charDim) / 2);
//System.out.println("x=" + x + " height=" + height + " charDim=" + charDim + " y=" + y + " advance=" + maxAdvance + " fontHeight=" + fontHeight + " ascent=" + fontMetrics.getAscent());
g.drawImage(charImage, (int) x, y, charDim, charDim, null, null);
charGraphics.dispose();
}
// let's do the border
g.setColor(borderColor);
g.drawRect(0, 0, width - 1, height - 1);
//Write the image as a jpg
Iterator iter = ImageIO
.getImageWritersByFormatName(imageFormat);
if (iter.hasNext()) {
ImageWriter writer = (ImageWriter) iter.next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
if (imageFormat.equalsIgnoreCase("jpg")
|| imageFormat.equalsIgnoreCase("jpeg")) {
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(imageQuality);
}
writer.setOutput(ImageIO.createImageOutputStream(response.getOutputStream()));
IIOImage imageIO = new IIOImage(bufferedImage, null, null);
writer.write(null, imageIO, iwp);
} else {
throw new RuntimeException("no encoder found for jsp");
}
// set session
request.getSession().setAttribute("captcha", finalString.toString());
System.out.println("Captcha.jsp: "+request.getSession().getAttribute("captcha"));//for console output
out.clear();
out = pageContext.pushBody();
g.dispose();
} catch (IOException ioe) {
throw new RuntimeException("Unable to build image", ioe);
}
%>
<%!public static String paramString(HttpServletRequest request,
String paramName, String defaultString) {
return request.getParameter(paramName) != null ? request
.getParameter(paramName) : defaultString;
}
public static int paramInt(HttpServletRequest request, String paramName,
int defaultInt) {
return request.getParameter(paramName) != null ? Integer
.parseInt(request.getParameter(paramName)) : defaultInt;
}%>
To set sesion I'm using - request.getSession().setAttribute("captcha", finalString.toString());
ValidateCapture.jsp:
<html>
<head>
<script type="text/javascript">
function ValidateCaptcha(){
<%String captcha=(String)request.getSession().getAttribute("captcha");%>
var answer = document.getElementById("answer").value;
var captcha = '<%=captcha%>';
if(answer==captcha){
alert('Yes');
}
else{
alert('No');
}
}
</script>
</head>
<body>
<img src="Captcha.jsp"/>
<input id="answer" type="text">
<input type="button" value="Submit" onclick="ValidateCaptcha();">
<%System.out.println("ValidateCapture.jsp: "+request.getSession().getAttribute("captcha"));%> <!--for console output-->
</body>
To get session I'm using - request.getSession().getAttribute("captcha");
Console Output:
i saw the code. expecially about set session. i thought you shouldn't set attribute value. First, session invalid just when The browser closed or no-operation time up 30 mins in tomcat configuration file. however,you didn't close your browser,you will get the same captcha with previous value of it. so, we can do this,follow the code: request.setAttribute("captcha", finalString.toString());//set value and request.getAttribute("captcha");//get value
like this.we will get different captcha values when we click the pictures.Request Object also changed. why do this? because when "Request" to server and server responsed later,request Object invalid. next request will produce new request object.just this,good luck.

Apache PDFBox Java library - Is there an API for creating tables?

I am using the Apache PDFBox java library to create PDFs. Is there a way to create a data-table using pdfbox? If there is no such API to do it, I would require to manually draw the table using drawLine etc., Any suggestions on how to go about this?
Source: Creating tables with PDFBox
The following method draws a table with the specified table content. Its a bit of a hack and will work for small strings of text. It does not perform word wrapping, but you can get an idea of how it is done. Give it a go!
/**
* #param page
* #param contentStream
* #param y the y-coordinate of the first row
* #param margin the padding on left and right of table
* #param content a 2d array containing the table data
* #throws IOException
*/
public static void drawTable(PDPage page, PDPageContentStream contentStream,
float y, float margin,
String[][] content) throws IOException {
final int rows = content.length;
final int cols = content[0].length;
final float rowHeight = 20f;
final float tableWidth = page.findMediaBox().getWidth() - margin - margin;
final float tableHeight = rowHeight * rows;
final float colWidth = tableWidth/(float)cols;
final float cellMargin=5f;
//draw the rows
float nexty = y ;
for (int i = 0; i <= rows; i++) {
contentStream.drawLine(margin, nexty, margin+tableWidth, nexty);
nexty-= rowHeight;
}
//draw the columns
float nextx = margin;
for (int i = 0; i <= cols; i++) {
contentStream.drawLine(nextx, y, nextx, y-tableHeight);
nextx += colWidth;
}
//now add the text
contentStream.setFont( PDType1Font.HELVETICA_BOLD , 12 );
float textx = margin+cellMargin;
float texty = y-15;
for(int i = 0; i < content.length; i++){
for(int j = 0 ; j < content[i].length; j++){
String text = content[i][j];
contentStream.beginText();
contentStream.moveTextPositionByAmount(textx,texty);
contentStream.drawString(text);
contentStream.endText();
textx += colWidth;
}
texty-=rowHeight;
textx = margin+cellMargin;
}
}
Usage:
PDDocument doc = new PDDocument();
PDPage page = new PDPage();
doc.addPage( page );
PDPageContentStream contentStream = new PDPageContentStream(doc, page);
String[][] content = {{"a","b", "1"},
{"c","d", "2"},
{"e","f", "3"},
{"g","h", "4"},
{"i","j", "5"}} ;
drawTable(page, contentStream, 700, 100, content);
contentStream.close();
doc.save("test.pdf" );
I created a small api for creating tables using PDFBox.
It can be found on github ( https://github.com/dhorions/boxable ) .
A sample of a generated pdf can be found here http://goo.gl/a7QvRM.
Any hints or suggestions are welcome.
Since I had the same problem some time ago I started to build a small library for it which I am also trying to keep up to date.
It uses Apache PDFBox 2.x and can be found here:
https://github.com/vandeseer/easytable
It allows for quite some customizations like setting the font, background color, padding etc. on the cell level, vertical and horizontal alignment, cell spanning, word wrapping and images in cells.
Drawing tables across several pages is also possible.
You can create tables like this for instance:
The code for this example can be found here – other examples in the same folder as well.
The accepted answer is nice but it will work with Apache PDFBox 1.x only, for Apache PDFBox 2.x you will need to modify a little bit the code to make it work properly.
So here is the same code but that is compatible with Apache PDFBox 2.x:
The method drawTable:
public static void drawTable(PDPage page, PDPageContentStream contentStream,
float y, float margin, String[][] content) throws IOException {
final int rows = content.length;
final int cols = content[0].length;
final float rowHeight = 20.0f;
final float tableWidth = page.getMediaBox().getWidth() - 2.0f * margin;
final float tableHeight = rowHeight * (float) rows;
final float colWidth = tableWidth / (float) cols;
//draw the rows
float nexty = y ;
for (int i = 0; i <= rows; i++) {
contentStream.moveTo(margin, nexty);
contentStream.lineTo(margin + tableWidth, nexty);
contentStream.stroke();
nexty-= rowHeight;
}
//draw the columns
float nextx = margin;
for (int i = 0; i <= cols; i++) {
contentStream.moveTo(nextx, y);
contentStream.lineTo(nextx, y - tableHeight);
contentStream.stroke();
nextx += colWidth;
}
//now add the text
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12.0f);
final float cellMargin = 5.0f;
float textx = margin + cellMargin;
float texty = y - 15.0f;
for (final String[] aContent : content) {
for (String text : aContent) {
contentStream.beginText();
contentStream.newLineAtOffset(textx, texty);
contentStream.showText(text);
contentStream.endText();
textx += colWidth;
}
texty -= rowHeight;
textx = margin + cellMargin;
}
}
The Usage updated to use the try-with-resources statement to close the resources properly:
try (PDDocument doc = new PDDocument()) {
PDPage page = new PDPage();
doc.addPage(page);
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
String[][] content = {{"a", "b", "1"},
{"c", "d", "2"},
{"e", "f", "3"},
{"g", "h", "4"},
{"i", "j", "5"}};
drawTable(page, contentStream, 700.0f, 100.0f, content);
}
doc.save("test.pdf");
}

Categories

Resources