Skip to main content
Known Participant
October 14, 2008
Question

Curved text with CFImage

  • October 14, 2008
  • 2 replies
  • 753 views
Hello,

Does anyone know if you can do curved text in CFImage? I know there's ImageDrawText, but I'm not sure if it can do curves.

Thanks,

Peter
    This topic has been closed for replies.

    2 replies

    Fernis
    Inspiring
    October 15, 2008
    There's ImageRotateDrawingAxis() function in CF8. With skill (and probably a ton of work and testing), this might be used to implement a curved text functionality. However, such hand written routine would have to know the font used, know how wide each letter of the font is - and do the math based on that, write one letter at a time, etc.

    So I'd say it's possible, and it would be actually fun to prove it, but it might not be worth the trouble...
    Inspiring
    October 15, 2008
    Fernis wrote:
    > So I'd say it's possible, and it would be actually fun to prove it, but it might not be worth the trouble...

    Yes, it is possible with java. So there may well be a combination of CF functions you could use to achieve this. However, the svg route (or something similar) may be quicker. You can easily create curved text with Inkscape, making it simpler to implement IMO.
    peterswanAuthor
    Known Participant
    October 20, 2008
    Here's what I came up with but the text appears jagged with smaller fonts. I think it's because the arc falls in between two coordinates sometimes, making it impossible to land on the correct pixel each time. Or maybe there's another reason? Thanks to cfsearching who came up with the font measurement technique. I might end up going with some third party tool.

    Here it is:

    <cfset img = ImageNew("", 400, 400)>

    <cfset Text2Write = "FRED SMITH FOR PRESIDENT">

    <!--- 1 for upper curve, 0 for lower curve --->
    <cfset isUpper = 1>

    <cfset textFont = "arial">
    <cfset textStyle = "bold">
    <cfset textSize = "20">
    <cfset ImageSetDrawingColor(img,"WHITE")>
    <cfset ImageSetAntialiasing(img,"on")>

    <cfset attr = { font="#textFont#", style="#textStyle#", size="#textSize#" }>

    <!--- get the width of the string --->
    <cfscript>
    Font = CreateObject("java", "java.awt.Font");
    text = {string = "#Text2Write#" };
    text.prop = { font="#textFont#", style="#textStyle#", javaStyle= BitOr(Font.BOLD, Font.ITALIC), size="#textSize#" };

    arguments.style = "#textStyle#";
    switch (arguments.style) {
    case "bold":
    text.prop.style = font.BOLD;
    break;
    case "italic":
    text.prop.style = font.ITALIC;
    break;
    case "bolditalic":
    text.prop.style = BitOr( Font.BOLD, Font.ITALIC);
    break;
    case "plain":
    text.prop.style = Font.PLAIN;
    break;
    default:
    text.prop.style = Font.PLAIN;
    break;
    }

    graphics = ImageGetBufferedImage( img ).getGraphics();
    currentFont = Font.init( javacast("string", text.prop.font), javacast("int", text.prop.javaStyle), javacast("int", text.prop.size));
    fontMetrics = graphics.getFontMetrics( currentFont );
    fontBounds = fontMetrics.getStringBounds( javacast("string", text.string), graphics );
    textString.width = fontBounds.getWidth();
    graphics.dispose();
    </cfscript>

    <cfset radius = 110>
    <cfset centerX = 200>
    <cfset centerY = 200>

    <!--- for some reason 270 is the top of the circle --->
    <cfif isUpper is 1>
    <cfset angle = 270>
    <cfelse>
    <cfset angle = 90>
    </cfif>


    <!--- character spacing --->
    <cfset angleIncrement = .54>

    <cfif isUpper is 1>
    <cfset angle = angle - ((textString.width / 2) * angleIncrement)>
    <cfelse>
    <cfset angle = angle + ((textString.width / 2) * angleIncrement)>
    </cfif>

    <cfloop from="1" to="#len(Text2Write)#" index="idx">

    <cfset singleChar = mid(Text2Write, idx, 1)>

    <!--- get the width of the char --->
    <cfscript>
    Font = CreateObject("java", "java.awt.Font");
    text = { x = 50, y = 100, string = "#singleChar#" };
    text.prop = { font="#textFont#", style="#textStyle#", javaStyle= BitOr(Font.BOLD, Font.ITALIC), size="#textSize#" };
    arguments.style = "#textStyle#";
    switch (arguments.style) {
    case "bold":
    text.prop.style = font.BOLD;
    break;
    case "italic":
    text.prop.style = font.ITALIC;
    break;
    case "bolditalic":
    text.prop.style = BitOr( Font.BOLD, Font.ITALIC);
    break;
    case "plain":
    text.prop.style = Font.PLAIN;
    break;
    default:
    text.prop.style = Font.PLAIN;
    break;
    }

    graphics = ImageGetBufferedImage( img ).getGraphics();
    currentFont = Font.init( javacast("string", text.prop.font), javacast("int", text.prop.javaStyle), javacast("int", text.prop.size));
    fontMetrics = graphics.getFontMetrics( currentFont );
    fontBounds = fontMetrics.getStringBounds( javacast("string", text.string), graphics );
    charItem.width = fontBounds.getWidth();
    graphics.dispose();
    </cfscript>


    <!--- get coordinates for the char --->
    <cfset theta = pi() * (angle / 180.0)>

    <cfset circleX = round(centerX + radius * cos(theta))>
    <cfset circleY = round(centerY + radius * sin(theta))>

    <cfif isUpper is 1>
    <cfset rotateAngle = angle + 90>
    <cfelse>
    <cfset rotateAngle = angle - 90>
    </cfif>

    <!--- rotate the char --->
    <cfset ImageRotateDrawingAxis(img, rotateAngle, circlex, circley)>

    <cfset ImageDrawText(img, "#singleChar#", circlex, circley, attr)>

    <!--- reset rotation --->
    <cfset ImageRotateDrawingAxis(img, -(rotateAngle), circlex, circley)>

    <cfif isUpper is 1>
    <cfset angle = angle + (angleIncrement * charItem.width)>
    <cfelse>
    <cfset angle = angle - (angleIncrement * charItem.width)>
    </cfif>


    </cfloop>

    <cfimage action="writeToBrowser" source="#img#">
    Inspiring
    October 15, 2008
    peterswan wrote:
    > Does anyone know if you can do curved text in CFImage?

    I could be wrong, but I would be surprised if it supports curves. If not, you might look into using svg and Batik. You could use Inkscape to create the svg and then use the output to generate an image in CF.

    http://rickosborne.org/blog/index.php/2008/01/28/generating-scalable-stretchy-and-smart-graphics-with-coldfusion-part-1/
    http://rickosborne.org/blog/index.php/category/programming/coldfusion/page/3/