Image generation through a java agent

Does anyone have a sample code of image generation using a java agent. I dont; want to go thru servlet route . I am trying to build a captcha.will be good if anyone has a code that i can use to start with...
LVL 14
Who is Participating?
Had you seen this ? It's a rant for a missing method basically but it also have the way to build a captcha in a  JSP (if you prefer to turn it into servlet, it is trivial when you have the JSP after all)
p_parthaAuthor Commented:
Thanks , Yeah i did see it. I dont' want to save images on the disk and generate images on the fly.. So checking whether there are any other innovative approaches

Thanks again
Not that I know of - last time I looked at it, that was the only way.
Which version of the server?
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

You've seen this one?

Also, if your requirement is to avoid disk I/O, there's a comment in the article Venabili posted:

    Jake White * Posted on Tue 17 Jun 2008 02:17 PM
p_parthaAuthor Commented:
Server version is 8.x.

Mbonaci..i cannot use recaptcha as it depends on a external server's response..which can be problematic, if the server is down or experiencing problems.. It has to be native. Forget abt captcha.. do you know of any sample code in java agent that can generate images , with that i can try building stuff... I am even ok with disk I/O after reading Jake's blog :(

Thanks both for your insights

- Partha
p_parthaAuthor Commented:

Thanks... This assumes that the image is in the nsf as a resource ... any idea whether i can send a dynamically created image to the browser as printwriter handles only text :(
>whether i can send a dynamically created image to the browser as printwriter handles only text

Nope, you cannot as far as I know. That's why I gave you the first link
Emmanuel GleizerCommented:
If I resume what you need: you want to send text only to the browser.
But you have to send an image (captcha): so this has to be base64/uuencoded (or what ever else).
Since you also need HTML form for the user to enter the code and submit it you may be abble to get the base64encoded in ajax, decode it and display it where you need (more detail see Picture.src = 'data:image/gif;base64,' + myBase64Data; in

this is the canvas...
good luck
p_parthaAuthor Commented:
Ok Guys , with help from and with my rusty java skills, i am able to write a captcha that works... no spl servlet.. just a agent (no spl permissions too)..

If you guys are interested.. i will put the code and explain what i did...
By all means, post the code and you explanation...

You can post that on OpenNTF or on IBM's Lotus Notes and Domino Application Development wiki ( also.
p_parthaAuthor Commented:
Ok Here we go...

First create a form and put the following passthru html in the following order:

<span id='filename'></span>
<img id='imagename' src='' alt='loading image'>

<script src='http://yoururltotheagent?openagent&someuniquevalue''></script>

Put the following code in a java agent.... Most of the stuff is self explanatory... I am hashing the filename with the image text using session.hashpassword .
This way i dont' need the document that gets created (coolest part) I have a scheduled agent that deletes the document immediately once it's created (agent runs when new documents are created or modified)...

Now when the verification part comes.. ALL i have to do is check the filename span tag with the value that is being entered using verifypassword in a simple lotusscript agent :)

Guys , i need comments on whether u see any risk in this approach...

- Partha

import lotus.domino.*;
import java.util.*;
import java.lang.*;

import java.awt.*;
import java.awt.image.*;
import javax.imageio.*;
import java.awt.geom.*;

public class JavaAgent extends AgentBase {

	public void NotesMain() {

		try {
			Session session = getSession();
			AgentContext agentContext = session.getAgentContext();
PrintWriter pw = getAgentOutput();
Database db = agentContext.getCurrentDatabase();
 Document doc = agentContext.getDocumentContext();

String imageFormat = "jpg";

   // you can pass in fontSize, width, height via the request
   Color backgroundColor =;
   Color borderColor =;
   Color textColor = Color.white;
   Color circleColor = new Color(160,160,160);
   Font textFont = new Font("Arial", Font.PLAIN, 24);
   int charsToPrint = 6;
   int width = 150;
   int 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.fillRect(0, 0, width, height);

   // lets make some noisey circles
   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);


   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];

     // 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;

     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);


   // let's do the border
   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);
     ImageWriteParam iwp = writer.getDefaultWriteParam();
     if ( imageFormat.equalsIgnoreCase("jpg") || imageFormat.equalsIgnoreCase("jpeg") ) {
     ByteArrayOutputStream os = new ByteArrayOutputStream();
	IIOImage imageIO = new IIOImage(bufferedImage, null, null);
	writer.write(null, imageIO, iwp);

	Now we ned to put the generated byte code in to a Notes Stream!

	Stream stream=session.createStream();
	stream.write( os.toByteArray() );

	Now let's create a document to store the new image in

	Document tmp = db.createDocument();
	tmp.replaceItemValue("Form", "Captcha");

	doc refers to the request for the image (captcha.jpg?openagent&832jrnj3nrj32kn)
	finalString refers to a random string of characters generated by the omitted code.

	String id = doc.getItemValueString("Query_String").replaceAll("openagent&", "");

	tmp.replaceItemValue("ID", id);
	String filename =session.hashPassword(finalString.toString())+".jpg";

	Now for the clever bit. Let's attach the file to our new document

	MIMEEntity Body = tmp.createMIMEEntity();

	MIMEHeader header = Body.createHeader("content-disposition");

	Body.setContentFromBytes(stream, "image/jpeg", MIMEEntity.ENC_IDENTITY_BINARY);;

pw.println("Content-Type: text/js");
pw.println("[document.getElementById(\"imagename\").src=' /"+db.getFilePath().replaceAll("\\\\", "/")+"/0/"+tmp.getUniversalID() + "/$file/"+filename+"']");

/*     writer.setOutput(ImageIO.createImageOutputStream());
     IIOImage imageIO = new IIOImage(bufferedImage, null, null);
     writer.write(null, imageIO, iwp);*/
   } else {
     throw new RuntimeException("no encoder found for jsp");

		} catch(Exception e) {

Open in new window

p_parthaAuthor Commented:
Also if any of the experts can test and see this, it will be great

So you just create it on the server and delete it immediatelly? Technically this is still not on the fly creation. Or am I missing something?
Great job!
Image generation is on the fly.
p_parthaAuthor Commented:
I dont' save anythign on the server. It's saved as a attachment for a document. the docucmnet gets deleted immediately, although the image url is sent to the browser..Hope i am clear.. if not pls do ask...

Mbonaci: thanks... cud u check whether are any loopholes in this approcah.. The only thing i am thiking is someone refreshing the page continuously.. and that leads to docs getting created in the backend.. Hopefuly my schedule agent can keep up with it...

Offtopic:  I am working on few things that are pretty challenging... I don't know whether i will be able to find out solution for those, but will the experts be interested in backing me up with pointers???, if yes then i will post, not sure whether i have enough points to post questions as i dont have time to answer questions nowadays...

Let me know guys.. and also am not sure why i posted this question under email server.. can this be moved to the lotus domino area, where experts like Sjef, qwal, maddy, crak,bill , and you guys can answer
p_parthaAuthor Commented:
Can i accept my solution itslef as answer?
We didn't help at all?
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.