Was this page helpful?

ColdFusion Captcha Component

    Table of contents
    1. 1. Captcha.cfm
    2. 2. Captcha.cfc

    Following is a ColdFusion Component which can create Captcha images. I don't use it anymore, but I didn't want to just delete it, so it is here for anyone who wants to use it.

     

    Captcha.cfm

    This file invokes the component to create the image and output a JPEG image. The component (below) can also save to a file.

    <cfinvoke component="components.Captcha" method="captchaToBinary" returnvariable="binary">
            <cfinvokeargument name="text" value="#session.captcha#" />
            <cfinvokeargument name="width" value="240" />
            <cfinvokeargument name="height" value="48" />
            <cfinvokeargument name="fontsize" value="34" />
            <cfinvokeargument name="leftOffset" value="20" />
            <cfinvokeargument name="topOffset" value="35" />
            <cfinvokeargument name="shearXRange" value="45" />
            <cfinvokeargument name="shearYRange" value="60" />
    </cfinvoke>
    
    <cfcontent type="image/jpeg" variable="#binary#">
    

     

    Captcha.cfc

    This is the actual component.

    <cfcomponent name="Captcha" hint="Writes the captcha to a file">
            
    <cfscript>
            instance = StructNew();
    </cfscript>
    
    <!------------------------------------------- PUBLIC ------------------------------------------->
    <cffunction name="init" hint="Constructor" access="public" returntype="Captcha" output="false">
            <cfscript>
                    
                    return this;
            </cfscript>
    </cffunction>
    
    <cffunction name="captchaToFile" hint="Writes the captcha to the designated file path" access="public" returntype="void" output="false">
            <cfargument name="filePath" hint="The absolute path to the file the CAPTCHA is to be written to" type="string" required="Yes">
            <cfargument name="text" hint="The text to display" type="string" required="Yes">
            <cfargument name="width" hint="The width of the image" type="numeric" required="true">
            <cfargument name="height" hint="The height of the image" type="numeric" required="true">
            <cfargument name="fontsize" hint="The font size the text" type="numeric" required="true">
            <cfargument name="leftOffset" hint="The number of pixels of padding to put to the left of the text" type="numeric" required="true">
            <cfargument name="topOffset" hint="The number of pixels of padding to put to the top of the text" type="numeric" required="true">
            <cfargument name="shearXRange" hint="The amount to shear the font on the X axis" type="numeric" required="true">
            <cfargument name="shearYRange" hint="The amount to shear the font on the Y axis"  type="numeric" required="true">       
            
            <cfscript>
                    var fileOutputStream = createObject("java", "java.io.FileOutputStream").init(arguments.filePath);               
                    
                    writeToStream(fileOutputStream,
                                              arguments.text,
                                              arguments.width,
                                              arguments.height,
                                              arguments.fontsize,
                                              arguments.leftOffset,
                                              arguments.topOffset,
                                              arguments.shearXRange,
                                              arguments.shearYRange);
                        
                fileOutputStream.flush();
                fileOutputStream.close();
            </cfscript>     
    </cffunction>
    
    <cffunction name="captchaToBinary" hint="Returns the captcha as binary data for use in the cfcontent 'variable' attribute" access="public" returntype="any" output="false">
            <cfargument name="text" hint="The text to display" type="string" required="Yes">
            <cfargument name="width" hint="The width of the image" type="numeric" required="true">
            <cfargument name="height" hint="The height of the image" type="numeric" required="true">
            <cfargument name="fontsize" hint="The font size the text" type="numeric" required="true">
            <cfargument name="leftOffset" hint="The number of pixels of padding to put to the left of the text" type="numeric" required="true">
            <cfargument name="topOffset" hint="The number of pixels of padding to put to the top of the text" type="numeric" required="true">
            <cfargument name="shearXRange" hint="The amount to shear the font on the X axis" type="numeric" required="true">
            <cfargument name="shearYRange" hint="The amount to shear the font on the Y axis"  type="numeric" required="true">               
            <cfscript>
                    var byteOutputstream = createObject("java", "java.io.ByteArrayOutputStream").init();
                    
                    writeToStream(byteOutputstream,
                                              arguments.text,
                                              arguments.width,
                                              arguments.height,
                                              arguments.fontsize,
                                              arguments.leftOffset,
                                              arguments.topOffset,
                                              arguments.shearXRange,
                                              arguments.shearYRange);
                                              
                            
                    return byteOutputstream.toByteArray();
            </cfscript>
    </cffunction>
    
    <!------------------------------------------- PACKAGE ------------------------------------------->
    
    <!------------------------------------------- PRIVATE ------------------------------------------->
    
    <cffunction name="writeToStream" hint="Writes to a outputStream" access="private" returntype="void" output="false">
            <cfargument name="outputStream" hint="Gimme a java.io.OutputStream" type="any" required="Yes">
            <cfargument name="text" hint="The text to display" type="string" required="Yes">
            <cfargument name="width" hint="The width of the image" type="numeric" required="true">
            <cfargument name="height" hint="The height of the image" type="numeric" required="true">
            <cfargument name="fontsize" hint="The font size the text" type="numeric" required="true">
            <cfargument name="LeftOffset" hint="The number of pixels of padding to put to the left of the text" type="numeric" required="true">
            <cfargument name="TopOffset" hint="The number of pixels of padding to put to the top of the text" type="numeric" required="true">
            <cfargument name="shearXRange" hint="The amount to shear the font on the X axis" type="numeric" required="true">
            <cfargument name="shearYRange" hint="The amount to shear the font on the Y axis"  type="numeric" required="true">       
                    
            <cfscript>
    /* variables */
                    var counter = 0;        var characters = 0;             var top = 0;
                    var len = 0;            var size = 0;                   var left = 0;
                    var response = 0;       var char = 0;                   var encoder = 0;
                    var encoderParam = 0;
    
                    /* utils */
                    var staticArrays = createObject("java", "java.util.Arrays");
                    var staticCollections = createObject("java", "java.util.Collections");
                    
                    
                    /* prep image  */
                    var dimension = createObject("java", "java.awt.Dimension").init(width, height); 
                    var imageType = createObject("java", "java.awt.image.BufferedImage").TYPE_INT_RGB;      
                    var bufferedImage = createObject("java", "java.awt.image.BufferedImage").init(JavaCast("int", dimension.getWidth()), JavaCast("int", dimension.getHeight()), imageType);        
                    var graphics = bufferedImage.createGraphics();
                    
                    /* get the fonts */
                    var allFonts = staticArrays.asList(createObject("java", "java.awt.GraphicsEnvironment").getLocalGraphicsEnvironment().getAllFonts());
                    
                    /* drawing graphics here */
                    
                    /* background */
                    var startColor = createRandomLightGreyScaleColor();
                    var endColor = createRandomLightGreyScaleColor();
                    
                    var gradientPaint = createObject("java", "java.awt.GradientPaint").init(getRandomPointOnBorder(dimension), 
                                                                                                                                                                    startColor, 
                                                                                                                                                                    getRandomPointOnBorder(dimension),  
                                                                                                                                                                    endColor);
                    
                    var background = createObject("java", "java.awt.Rectangle").init(dimension);
                    
                    graphics.setPaint(gradientPaint);
                    graphics.fill(background);
                    
                    /* draw some lines */
                    len = randRange(10, 20);
                    for(counter = 1; counter lte len; counter = counter + 1)
                    {               
                            drawRandomLine(graphics, dimension);
                    }
                    
                    /* draw the text in random font characters */
                    characters = text.toCharArray();        
                    len = ArrayLen(characters);
                    
                    size = fontsize;
                    top = topOffset;
                    left = Leftoffset;
                    
                    staticCollections.shuffle(allFonts);
                    for(counter = 1; counter lte len; counter = counter + 1)
                    {
                            char = characters[counter];
                            setNewFont(graphics, allFonts, size, arguments.shearXRange, arguments.shearYRange);
                            graphics.setColor(createRandomDarkGreyScaleColor());
            
                            //if cannot display, find a font that can
                            while(NOT graphics.getFont().canDisplay(char))
                            {       
                                    setNewFont(graphics, allFonts, size, arguments.shearXRange, arguments.shearYRange);
                            }               
                            graphics.drawString(JavaCast("string", char), JavaCast("int", left), JavaCast("int", top));
                            left = left + (2 * graphics.getFontMetrics().charWidth(char));
                    }
                    
                    /* draw a few more lines */
                            
                    len = randRange(2, round(max(min(width, height) / 20, 3)));  //draw more lines the bigger it is.
                    for(counter = 1; counter lte len; counter = counter + 1)
                    {               
                            drawRandomLine(graphics, dimension);
                    }
            
                    
                    encoder = createObject("java", "com.sun.image.codec.jpeg.JPEGCodec").createJPEGEncoder(arguments.outputstream);
                    encoderParam = encoder.getDefaultJPEGEncodeParam(bufferedImage);
                    encoderParam.setQuality(JavaCast("float", 0.80), false);
                encoder.setJPEGEncodeParam(encoderParam);
                encoder.encode(bufferedImage);
            </cfscript>
    </cffunction>
    
    <cffunction name="createRandomLightGreyScaleColor" hint="Creates a random greyscale java.awt.colour" access="private" returntype="any" output="false">
            <cfscript>
                    var shade = JavaCast("int", RandRange(255, 160));
                    var color = createObject("java", "java.awt.Color").init(shade, shade, shade);
                    return color;           
            </cfscript>
    </cffunction>
    
    <cffunction name="createRandomDarkGreyScaleColor" hint="Returns a dark greyscale java.awt.color" access="private" returntype="any" output="false">
            <cfscript>
                    var shade = JavaCast("int", RandRange(0, 100));         
                    var color = createObject("java", "java.awt.Color").init(shade, shade, shade);
                    return color;
            </cfscript>
    </cffunction>
    
    <cffunction name="getRandomPointOnBorder" hint="Gets a random java.awt.Point on the border" access="private" returntype="any" output="false">
            <cfargument name="dimension" hint="The dimension object" type="any" required="Yes">
            <cfscript>
                    var point = createObject("java", "java.awt.Point");
                    var height = Javacast("int", arguments.dimension.getHeight());
                    var width = JavaCast("int", arguments.dimension.getWidth());
                    var choice = randrange(1,4);
                    switch (choice)
                    {
                            case 1: //left side
                                    point.setLocation(JavaCast("int", 0), JavaCast("int", RandRange(0, height)));
                            break;
                            case 2: //top side
                                    point.setLocation(JavaCast("int", RandRange(0, width)), JavaCast("int", 0));
                            break;
                            case 3: //right side
                                    point.setLocation(width, RandRange(0, height));
                            break;
                            case 4: //bottom side
                                    point.setLocation(RandRange(0, width), height);
                            break;          
                    }
                    
                    return point;                   
            </cfscript>
    </cffunction>
    
    <cffunction name="setNewFont" hint="Sets a new font in the graphics lib" access="private" returntype="void" output="false">
            <cfargument name="graphics" hint="The graphics" type="any" required="Yes">
            <cfargument name="fontCollection" hint="The current font collection" type="any" required="Yes">
            <cfargument name="size" hint="The size of the font" type="numeric" required="Yes">
            <cfargument name="shearXRange" hint="The shear x range" type="numeric" required="Yes">
            <cfargument name="shearYRange" hint="The shear y range" type="numeric" required="Yes">
            <cfscript>
                    var font = 0;
                    var staticCollections = createObject("java", "java.util.Collections");
                                                    
                    staticCollections.rotate(arguments.fontCollection, 1);
                    //apply transform twice, just for fun
                    font = arguments.fontCollection[1].deriveFont(JavaCast("float", arguments.size)).deriveFont(getRandomTransformation(arguments.shearXRange, arguments.shearYRange)).deriveFont(getRandomTransformation(arguments.shearXRange, arguments.shearYRange));
                    arguments.graphics.setFont(font);               
            </cfscript>
    </cffunction>
    
    <cffunction name="getRandomTransformation" hint="Gets a random transformation" access="private" returntype="any" output="false">
            <cfargument name="shearXRange" hint="The shear x range" type="numeric" required="Yes">
            <cfargument name="shearYRange" hint="The shear y range" type="numeric" required="Yes">
            <cfscript>
                    //create a slightly random affine transform
                    var transformation = createObject("java", "java.awt.geom.AffineTransform").init();
                    var shearx = RandRange(-1 * arguments.shearXRange, arguments.shearXRange) / 100;
                    var sheary = RandRange(-1 * arguments.shearYRange, arguments.shearYRange) / 100;
                    transformation.shear(shearx, sheary);
                    
                    return transformation;
            </cfscript>
    </cffunction>
    
    <cffunction name="drawRandomLine" hint="draws a random line" access="private" returntype="void" output="false">
            <cfargument name="graphics" hint="The graphics" type="any" required="Yes">
            <cfargument name="dimension" hint="The dimension object" type="any" required="Yes">
            <cfscript>              
                    var point1 = getRandomPointOnBorder(arguments.dimension);
                    var point2 = getRandomPointOnBorder(arguments.dimension);
                    var staticColor = createObject("java", "java.awt.Color");
                    
                    arguments.graphics.setColor(staticColor.white);
                    
                    arguments.graphics.drawLine(
                            JavaCast("int", point1.getX()), 
                            JavaCast("int", point1.getY()), 
                            JavaCast("int", point2.getX()), 
                            JavaCast("int", point2.getY()));
            
            </cfscript>
    </cffunction>
    
    </cfcomponent>
    
    Was this page helpful?
    Tag page (Edit tags)
    • No tags
    You must login to post a comment.
    Powered by MindTouch Core