You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by pi...@apache.org on 2005/09/05 02:14:29 UTC

svn commit: r278648 - in /cocoon/branches/BRANCH_2_1_X/src/blocks/captcha: ./ conf/ java/ java/org/ java/org/apache/ java/org/apache/cocoon/ java/org/apache/cocoon/reading/ samples/

Author: pier
Date: Sun Sep  4 17:14:22 2005
New Revision: 278648

URL: http://svn.apache.org/viewcvs?rev=278648&view=rev
Log:
Adding the "CAPTCHA" block as promised

Added:
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/captcha-reader.xmap
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/captcha.xsamples
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/java/
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/java/org/
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/java/org/apache/
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/java/org/apache/cocoon/
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/java/org/apache/cocoon/reading/
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/java/org/apache/cocoon/reading/CaptchaReader.java
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/captcha.js
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/custom.xhtml
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple-failure.jx
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple-success.jx
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple.jx
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/sitemap.xmap
    cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/welcome.xml

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/captcha-reader.xmap
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/captcha-reader.xmap?rev=278648&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/captcha-reader.xmap (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/captcha-reader.xmap Sun Sep  4 17:14:22 2005
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<xmap xmlns:map="http://apache.org/cocoon/sitemap/1.0"
+      xpath="/sitemap/components/readers"
+      unless="reader[@name='captcha']">
+
+    <map:reader name="captcha"
+                logger="sitemap.reader.captcha"
+                src="org.apache.cocoon.reading.CaptchaReader"/>
+</xmap>

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/captcha.xsamples
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/captcha.xsamples?rev=278648&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/captcha.xsamples (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/conf/captcha.xsamples Sun Sep  4 17:14:22 2005
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<xsamples xpath="/samples" unless="group[@name='CAPTCHA']">
+
+  <group name="CAPTCHA">
+    <sample name="CAPTCHA Block" href="captcha/">
+      Example usages of CAPTCHAs.
+    </sample>
+  </group>
+
+</xsamples>

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/java/org/apache/cocoon/reading/CaptchaReader.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/java/org/apache/cocoon/reading/CaptchaReader.java?rev=278648&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/java/org/apache/cocoon/reading/CaptchaReader.java (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/java/org/apache/cocoon/reading/CaptchaReader.java Sun Sep  4 17:14:22 2005
@@ -0,0 +1,310 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.reading;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.Random;
+
+import com.sun.image.codec.jpeg.JPEGCodec;
+import com.sun.image.codec.jpeg.JPEGEncodeParam;
+import com.sun.image.codec.jpeg.JPEGImageEncoder;
+
+/**
+ * <p>The {@link CaptchaReader} is a simple tool generating JPEG images for the text
+ * supplied as its source in a way so that it's hard to parse automatically.</p>
+ * 
+ * <p><i>CAPTCHA</i> means quite literally <i>Completely Automated Public Turing
+ * Test to Tell Computers and Humans Apart</i> and one of the best resources on
+ * this can be found at the <a href="http://www.captcha.net/">Carnegie Mellon
+ * School of Computer Science CAPTCHA project.</a>.
+ * 
+ * <p>This reader creates very simple <i>CAPTCHAs</i> from within a Cocoon pipeline,
+ * enabling quick and safe end-user presence identificat. As an example, look at the
+ * following pipeline snippet:</p>
+ * 
+ * <pre>
+ * &lt;map:match pattern="*"&gt;
+ *   &lt;map:read type="captcha" src="{1}"/&gt;
+ * &lt;/map:match&gt;
+ * </pre>
+ * 
+ * <p>The example will produce an image containing the text in <code>{1}</code>
+ * "warped" or "bent" in a way similar to the Adobe&reg; Photoshop&reg; "Wave"
+ * filter plugin.</p>
+ * 
+ * <p>Few pipeline parameters control the operation of the {@link CaptchaReader}
+ * (this component is not configurable):</p>
+ * 
+ * <ul>
+ *   <li><code>width</code>: the width of the image to generate (default: 100).</li>
+ *   <li><code>height</code>: the height of the image to generate (default: 50).</li>
+ *   <li><code>foreground</code>: the text foreground color (default: random).</li>
+ *   <li><code>background</code>: the image background color (default: white).</li>
+ *   <li><code>font</code>: the font to use for the text (default: serif).</li>
+ *   <li><code>scale</code>: the scaling factor for interim images (default: 5).</li>
+ *   <li><code>amount</code>: the amount of text warping to apply (default: 1).</li>
+ *   <li><code>quality</code>: the JPEG encoding quality (default: 0.75).</li>
+ * </ul>
+ * 
+ * <p>Note that when the <code>foreground</code> parameter is not specified, the
+ * color used to write the text will be randomly chosen in a way that it contrasts
+ * well with the background color to avoid problems of illegible text.</p>
+ * 
+ * <p>Both the <code>foreground</code> and <code>background</code> parameters accept
+ * strings in the format specified by {@link Color#decode(String)} (for example
+ * <code>fff</code>, or <code>0099CC</code>) or one of the field names of the
+ * {@link Color} class (for example {@link Color#BLACK BLACK} or {@link Color#cyan
+ * cyan} ...).</p>
+ * 
+ * <p>The <code>scale</code> parameter controls how much the specified size should
+ * be scaled while processing the interim images: the bigger the scaling factor, the
+ * better the image quality, but also the memory used while generating the final
+ * image will be bigger. In other words, use with care.</p>
+ * 
+ * <p>The <code>amount</code> parameter is interpreted as a floating point number
+ * and must be greater than zero. This controls how much text should be warped, and
+ * normally a value of <code>1</code> produce quite-good warping. Increasing (or
+ * decreasing) this value will produce more (ore less) warping.</p>
+ *
+ * <p>Remember that in no way the {@link CaptchaReader} claims to be able to
+ * generate "unbreakable" text (that will be impossible), and improvements to the
+ * algorithm are welcome.</p>
+ *
+ * @author <a href="mailto:pier@betaversion.org">Pier Fumagalli</a>
+ */
+public class CaptchaReader extends AbstractReader {
+    
+    /** <p>A unique {@link Random} instance to use.</p> */
+    private static final Random RANDOM = new Random();
+
+    /**
+     * <p>The content type of the generated content: <code>image/jpeg</code>.</p>
+     *
+     * @return Always <code>image/jpeg</code>.
+     */
+    public String getMimeType() {
+        return "image/jpeg";
+    }
+
+    /**
+     * <p>Return a {@link Color} instance from a specified parameter.</p>
+     *
+     * @param parameterName The name of the parameter whose to use as the color.
+     * @param defaultColor The default {@link Color} to return.
+     * @return the interpreted color or the default color specified.
+     */
+    private Color getColor(String parameterName, Color defaultColor) {
+        String colorString = this.parameters.getParameter(parameterName, null);
+        if (colorString == null) return defaultColor;
+        try {
+            return Color.decode(colorString);
+        } catch (Exception e1) {
+            try {
+                Field colorField = Color.class.getDeclaredField(colorString);
+                return (Color) colorField.get(Color.class);
+            } catch (Exception e2) {
+                return defaultColor;
+            }
+        }
+    }
+    
+    private Graphics2D antialiasedGraphics(BufferedImage image) {
+        Graphics2D graphics = image.createGraphics();
+        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+                                  RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+        return graphics;
+    }
+
+    /**
+     * <p>Create an image containing the text specified as this reader source
+     * warped to avoid automatic interpretation.</p>
+     *
+     * @throws IOException if an I/O error occurred generating the image.
+     */
+    public void generate()
+    throws IOException {
+
+        /* Retrieve the current operational parameters from Cocoon's sitemap */
+        final int width = this.parameters.getParameterAsInteger("width", 100);
+        final int height = this.parameters.getParameterAsInteger("height", 50);
+        Color background = this.getColor("background", Color.WHITE);
+        Color foreground = this.getColor("foreground", null);
+        if (foreground == null) {
+            int r = (RANDOM.nextInt(64) + 96 + background.getRed()) & 0x0ff;
+            int g = (RANDOM.nextInt(64) + 96 + background.getGreen()) & 0x0ff;
+            int b = (RANDOM.nextInt(64) + 96 + background.getBlue()) & 0x0ff;
+            foreground = new Color(r, g, b);
+        }
+        final String fontName = this.parameters.getParameter("font", "serif");
+        final int scale = this.parameters.getParameterAsInteger("scale", 5);
+        final float amount = this.parameters.getParameterAsFloat("amount", 2);
+        final float quality = this.parameters.getParameterAsFloat("quality", 0.75F);
+        final String text = this.source;
+
+        /* Create the final buffered image we will be writing to at the bottom */
+        final BufferedImage result = new BufferedImage(width, height,
+                                                       BufferedImage.TYPE_INT_RGB);
+
+        /* Starting with a size of 100, evaluate how big the real font should be */
+        final Font baseFont = new Font(fontName, Font.PLAIN, 100);
+        final Graphics2D graphics = this.antialiasedGraphics(result);
+        final FontMetrics metrics = graphics.getFontMetrics(baseFont);
+        final Rectangle2D tempSize = metrics.getStringBounds(text, graphics);
+
+        /* Evaluate the image size of the resulting image and prepare a ratio */
+        final double tempWidth = tempSize.getWidth() + (2 * tempSize.getHeight());
+        final double tempHeight = (tempSize.getHeight() * (1 + amount));
+        final double ratioWidth = width * scale / tempWidth;
+        final double ratioHeight = height * scale / tempHeight;
+        final double ratio = ratioWidth < ratioHeight? ratioWidth: ratioHeight;
+        final Font font = baseFont.deriveFont((float) (100 * ratio));
+
+        /* Evaluate the final size of the text to write */
+        final FontMetrics sourceMetrics = graphics.getFontMetrics(font);
+        final Rectangle2D size = sourceMetrics.getStringBounds(text, graphics);
+        final double textWidth = size.getWidth();
+        final double textHeight = size.getHeight();
+
+        /* Evaluate the final size of the interim images */
+        int scaledWidth = (int) (tempWidth * ratio);
+        int scaledHeight = (int) (tempHeight * ratio);
+        
+        /* Create a couple of images to write the plain string and the warped one */
+        BufferedImage source = new BufferedImage(scaledWidth, scaledHeight,
+                                                 BufferedImage.TYPE_BYTE_GRAY);
+        BufferedImage warped = new BufferedImage(scaledWidth, scaledHeight,
+                                                 BufferedImage.TYPE_INT_ARGB);
+
+        /* Prepare the background and the font of the source image */
+        final Graphics2D sourceGraphics = this.antialiasedGraphics(source);
+        sourceGraphics.setColor(Color.BLACK);
+        sourceGraphics.fillRect(0, 0, scaledWidth, scaledHeight);
+        sourceGraphics.setFont(font);
+
+        /* Write the string exactly in the middle of the source image */
+        float textX = (float) ((scaledWidth  - textWidth)  / 2); 
+        float textY = (float) ((scaledHeight - textHeight) / 2);
+        sourceGraphics.setColor(Color.WHITE);
+        sourceGraphics.drawString(text, textX, textY + sourceMetrics.getAscent());
+
+        /* Randomize displacement factors for sine-waves */
+        final int displaceTop = RANDOM.nextInt(scaledWidth);
+        final int displaceBtm = RANDOM.nextInt(scaledWidth);
+        final int displaceVer = RANDOM.nextInt(scaledHeight);
+
+        /* Calculate the horizontal and vertical amplitude and wavelength of sines */
+        final double amplitHor = textHeight * amount / 4;
+        final double amplitVer = textHeight / 8;
+        final double t = (RANDOM.nextDouble() * textWidth / 2) + (textWidth * 0.75);
+        final double b = (RANDOM.nextDouble() * textWidth / 2) + (textWidth * 0.75);
+        final double wlenTop = textHeight > t? textHeight: t;
+        final double wlenBtm = textHeight > b? textHeight: b;
+
+        /* Calculate the offsets for horizontal (top and bottom) sine waves */
+        final double offsetTop = amplitHor;
+        final double offsetBtm = scaledHeight - amplitHor;
+
+        /* Prepare an array for vertical displacement sine wave */
+        final double vert[] = new double[scaledHeight];
+        for (int v = 0; v < scaledHeight ; v++) {
+            vert[v] = Math.sin((Math.PI * (v + displaceVer)) / textHeight) * amplitVer;
+        }
+
+        /* Iterate all the target image pixels and render the distortion */
+        int x1 = Integer.MAX_VALUE;
+        int x2 = Integer.MIN_VALUE;
+        int y1 = Integer.MAX_VALUE;
+        int y2 = Integer.MIN_VALUE;
+        final WritableRaster sourceRaster = source.getRaster();
+        final WritableRaster warpedRaster = warped.getRaster();
+        final double src[] = new double[9];
+        final double col[] = new double[] { foreground.getRed(),
+                                            foreground.getGreen(),
+                                            foreground.getBlue(), 0};
+        for (int h = 0; h < scaledWidth; h++) {
+            final double baseTop = (Math.PI * (h + displaceTop)) / wlenTop;
+            final double baseBtm = (Math.PI * (h + displaceBtm)) / wlenBtm; 
+            final double top = offsetTop + Math.sin(baseTop) * amplitHor;
+            final double btm = offsetBtm - Math.sin(baseBtm) * amplitHor;
+
+            for (int v = 0; v < scaledHeight; v ++) {
+                final double x = (h + vert[v]);
+                final double y = (v * ((btm - top) / scaledHeight)) + top;
+
+                if ((y > 0) && (y < scaledHeight - 1) &&
+                    (x > 0) && (x < scaledWidth - 1)) {
+
+                    /* Retrieve the nine pixels around the source one */
+                    sourceRaster.getPixels((int)(x-1), (int)(y-1), 3, 3, src);
+
+                    /* Average their value (it's grayscale) to have a better warp */
+                    double alpha = ((src[1] + src[3] + src[5] + src[7]) * 0.1) +
+                                   ((src[0] + src[2] + src[6] + src[8]) * 0.025) +
+                                   (src[4] * 0.5);
+
+                    /* Write the resultin pixel in the target image if necessary */
+                    if (alpha > 0) {
+                        col[3] = alpha;
+                        warpedRaster.setPixel(h, v, col);
+                        if (h < x1) x1 = h;
+                        if (h > x2) x2 = h;
+                        if (v < y1) y1 = v;
+                        if (v > y2) y2 = v;
+                    }
+                }
+            }
+        }
+
+        /* Crop the image to the maximum extent of the warped text (if visible) */
+        source = null;
+        int xd = x2 - x1 + 1;
+        int yd = y2 - y1 + 1; 
+        if ((xd > 1) && (yd > 1)) {
+            warped = warped.getSubimage(x1, y1, xd, yd);
+        }
+
+        /* Rescale the cropped image to the required size */
+        Image image = warped.getScaledInstance(width, height, Image.SCALE_SMOOTH);
+        graphics.setBackground(background);
+        graphics.setColor(background);
+        graphics.fillRect(0, 0, width, height);
+        graphics.setColor(foreground);
+        graphics.drawImage(image, 0, 0, null);
+        warped = null;
+
+        /* Write the processed image as a JPEG image */
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(buffer);
+        JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(result);
+        param.setQuality(quality, true);
+        encoder.encode(result, param);
+        buffer.flush();
+        buffer.close();
+        this.out.write(buffer.toByteArray());
+        this.out.flush();
+    }
+}

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/captcha.js
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/captcha.js?rev=278648&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/captcha.js (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/captcha.js Sun Sep  4 17:14:22 2005
@@ -0,0 +1,35 @@
+function passcode(length) {
+  var alphabet = [ 'a', 'a', 'a', 'b', 'c', 'd', 'e', 'e', 'e', 'f', 'g', 'h', 'i',
+                   'i', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'o', 'o', 'p', 'q', 'r',
+                   's', 't', 'u', 'u', 'u', 'v', 'w', 'x', 'y', 'z' ]; 
+
+  var result = "";
+  for (var x = 0; x < length; x++) {
+    var offset = Math.random() * alphabet.length;
+    result += alphabet[Math.floor(offset)];
+  }
+  return result;
+} 
+
+function simple() {
+  var session = cocoon.session;
+
+  session.setAttribute("captcha", passcode(7));
+  cocoon.sendPageAndWait("simple.jx");
+  var parameters = null;
+
+  while (true) {
+    parameters = {
+      "supplied": cocoon.request["captcha"],
+      "expected": session.getAttribute("captcha"),
+    };
+
+    if (parameters['supplied'].equals(parameters['expected'])) break;
+
+    session.setAttribute("captcha", passcode(7));
+    cocoon.sendPageAndWait("simple-failure.jx", parameters);
+  }
+
+  session.invalidate();
+  cocoon.sendPageAndWait("simple-success.jx", parameters);
+}

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/custom.xhtml
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/custom.xhtml?rev=278648&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/custom.xhtml (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/custom.xhtml Sun Sep  4 17:14:22 2005
@@ -0,0 +1,53 @@
+<html>
+  <head>
+    <title>Customize your CAPTCHAs</title>
+    <script language="javascript">//<!--
+      function generate(form) {
+        var imageuri = "custom.jpeg";
+        imageuri += "?text="       + form['text'].value;
+        imageuri += "&width="      + form['width'].value;
+        imageuri += "&height="     + form['height'].value;
+        imageuri += "&background=" + form['background'].value;
+        imageuri += "&foreground=" + form['foreground'].value;
+        imageuri += "&font="       + form['font'].value;
+        imageuri += "&scale="      + form['scale'].value;
+        imageuri += "&amount="     + form['amount'].value;
+        imageuri += "&quality="    + form['quality'].value;
+        imageuri += "&random="     + Math.random();
+        if (document.all) {
+          document.all['captcha'].src = imageuri;
+        } else {
+          document.getElementById('captcha').src = imageuri;
+        }
+        return(false);
+      }
+    //--></script>
+  </head>
+  <body onload="generate(document.forms['form']);">
+    <div style="text-align: center">
+      <p><a href="welcome">Back to the samples</a></p>
+
+      <p>
+        This page demonstrate the capabilities of
+        Cocoon's <code>CaptchaReader</code>.
+      </p>
+
+      <form id="form" onsubmit="return generate(this);">
+        <table border="0" align="center" cellspacing="0" cellpadding="0">
+          <tr><td><input type="text" name="text"       value="welcome"/></td><td>The text to render</td></tr>
+          <tr><td><input type="text" name="width"      value="100"/></td>    <td>The width of the image.</td></tr>
+          <tr><td><input type="text" name="height"     value="50"/></td>     <td>The height of the image.</td></tr>
+          <tr><td><input type="text" name="background" value="white"/></td>  <td>The background color of the image.</td></tr>
+          <tr><td><input type="text" name="foreground" value="black"/></td>  <td>The foreground color of the image.</td></tr>
+          <tr><td><input type="text" name="font"       value="serif"/></td>  <td>The font used to write the text.</td></tr>
+          <tr><td><input type="text" name="scale"      value="5"/></td>      <td>The scaling factor for rendering quality.</td></tr>
+          <tr><td><input type="text" name="amount"     value="1"/></td>      <td>The amount of text warping.</td></tr>
+          <tr><td><input type="text" name="quality"    value="0.75"/></td>   <td>The quality of the JPEG to produce.</td></tr>
+        </table>
+        <input type="submit" value="Generate"/>
+      </form>
+      
+      <img id="captcha"/>
+    </div>
+  </body>
+</html>

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple-failure.jx
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple-failure.jx?rev=278648&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple-failure.jx (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple-failure.jx Sun Sep  4 17:14:22 2005
@@ -0,0 +1,23 @@
+<html>
+  <head>
+    <title>Simple use of CAPTCHAs</title>
+  </head>
+  <body>
+    <div style="text-align: center">
+      <p><a href="welcome">Back to the samples</a></p>
+
+      <p>
+        Sorry, the value you entered "<code>${supplied}</code>" did not match the
+        expected captcha string "<code>${expected}</code>". Try again...
+      </p>
+
+      <form action="continue" method="post">
+        <img src="simple.jpeg" width="100" height="50"/><br />
+        Enter the text written in the image above and click on <b>Verify</b>.<br />
+        <input type="hidden" name="continuation" value="${continuation.id}"/>
+        <input type="text" name="captcha"/>
+        <input type="submit" value="Verify"/>
+      </form>
+    </div>
+  </body>
+</html>

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple-success.jx
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple-success.jx?rev=278648&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple-success.jx (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple-success.jx Sun Sep  4 17:14:22 2005
@@ -0,0 +1,17 @@
+<html>
+  <head>
+    <title>Simple use of CAPTCHAs</title>
+  </head>
+  <body>
+    <div style="text-align: center">
+      <p><a href="welcome">Back to the samples</a></p>
+      
+      <p>
+        Success, the value you entered "<code>${supplied}</code>" matches the
+        expected captcha string "<code>${expected}</code>".
+      </p>
+
+      <p><a href="welcome">Back to the samples</a></p>
+    </div>
+  </body>
+</html>

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple.jx
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple.jx?rev=278648&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple.jx (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/simple.jx Sun Sep  4 17:14:22 2005
@@ -0,0 +1,23 @@
+<html>
+  <head>
+    <title>Simple use of CAPTCHAs</title>
+  </head>
+  <body>
+    <div style="text-align: center">
+      <p><a href="welcome">Back to the samples</a></p>
+
+      <p>
+        This page demonstrate the use of a simple CAPTCHA, implemented using
+        Cocoon's <code>CaptchaReader</code> through server-side sessions.
+      </p>
+
+      <form action="continue" method="post">
+        <img src="simple.jpeg" width="100" height="50"/><br />
+        Enter the text written in the image above and click on <b>Verify</b>.<br />
+        <input type="hidden" name="continuation" value="${continuation.id}"/>
+        <input type="text" name="captcha"/>
+        <input type="submit" value="Verify"/>
+      </form>
+    </div>
+  </body>
+</html>
\ No newline at end of file

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/sitemap.xmap
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/sitemap.xmap?rev=278648&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/sitemap.xmap (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/sitemap.xmap Sun Sep  4 17:14:22 2005
@@ -0,0 +1,83 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--+
+    | HTML block samples sitemap
+    | CVS $Id: sitemap.xmap 230598 2005-08-06 21:53:09Z antonio $
+    +-->
+
+<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
+
+  <map:flow language="javascript">
+    <map:script src="captcha.js"/>
+  </map:flow>
+
+  <map:pipelines>
+    <map:pipeline type="caching">
+
+      <map:match pattern="">
+        <map:redirect-to uri="welcome"/>
+      </map:match>
+
+      <!-- list of samples -->
+      <map:match pattern="welcome">
+        <map:generate src="welcome.xml"/>
+        <map:transform src="context://samples/common/style/xsl/html/simple-samples2html.xsl">
+          <map:parameter name="contextPath" value="{request:contextPath}"/>
+        </map:transform>
+        <map:serialize/>
+      </map:match>
+      
+      <map:match pattern="custom">
+        <map:generate src="custom.xhtml"/>
+        <map:serialize type="html"/>
+      </map:match>
+      
+      <map:match pattern="simple">
+        <map:call function="simple"/>
+      </map:match>
+
+      <map:match pattern="continue">
+        <map:call continuation="{request-param:continuation}"/>
+      </map:match>
+
+      <map:match pattern="custom.jpeg">
+        <map:read type="captcha" src="{request-param:text}">
+          <map:parameter name="width"      value="{request-param:width}"/>
+          <map:parameter name="height"     value="{request-param:height}"/>
+          <map:parameter name="background" value="{request-param:background}"/>
+          <map:parameter name="foreground" value="{request-param:foreground}"/>
+          <map:parameter name="font"       value="{request-param:font}"/>
+          <map:parameter name="scale"      value="{request-param:scale}"/>
+          <map:parameter name="amount"     value="{request-param:amount}"/>
+          <map:parameter name="quality"    value="{request-param:quality}"/>
+        </map:read>
+      </map:match>
+
+      <map:match pattern="simple.jpeg">
+        <map:read type="captcha" src="{session-attr:captcha}"/>
+      </map:match>
+      
+      <map:match pattern="**.jx">
+        <map:generate type="jx" src="{1}.jx"/>
+        <map:serialize type="html"/>
+      </map:match>
+      
+
+    </map:pipeline>
+  </map:pipelines>
+</map:sitemap>

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/welcome.xml
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/welcome.xml?rev=278648&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/welcome.xml (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/captcha/samples/welcome.xml Sun Sep  4 17:14:22 2005
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!-- CVS $Id: samples.xml 230598 2005-08-06 21:53:09Z antonio $ -->
+
+<samples name="Captcha Block Samples" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <group name="Back">
+    <sample name="Back" href="../..">to Cocoon Samples main page</sample>
+    <sample name="Back" href="..">to Cocoon Blocks Samples main page</sample>
+  </group>
+
+  <group name="Captcha">
+    <sample name="Simple Captcha" href="simple">
+      Shows an example of how to use a simple CAPTCHA using FlowScript.
+    </sample>
+    <sample name="Custom Captcha" href="custom">
+      Shows a page helping the customization of CAPTCHAs.
+    </sample>
+  </group>
+
+  <group name="Avaliable Documentation">
+    <sample name="Captcha Block Documentation"
+            href="http://cocoon.zones.apache.org/daisy/documentation/blocks/captcha.html">
+      On-line documentation for the Captcha block.
+    </sample>
+    <sample name="CaptchaReader Documentation"
+            href="http://cocoon.zones.apache.org/daisy/documentation/components/readers/captchareader.html">
+      On-line documentation for the CaptchaReader component.
+    </sample>
+  </group>
+    
+
+</samples>