The Coldfusion Open Source Forums
Home | ImageCFC | CFFM | BlogCFM | CFMBB | CFOpenMail / ImapCFC | CFOpenChat
Forums | Profile | Inbox | Members | Chat | Search | Login | RSS
Vivio Technologies Dedicated Hosting
New Topic Reply Subscription Options   Previous Page  Page: 1   Previous Page

Forums: ImageCFC Forum: Placing Centered Text on a Graphic
Created on: 09/10/07 {ts '2018-12-15 18:26:00'} Views: 8282 Replies: 4
Placing Centered Text on a Graphic
Posted Monday, September 10, 2007 at {ts '2018-12-15 18:26:00'}

Howdy all.

Firstly, I'll say thank to Rick Root for writing this very cool CFC. It's come in handy for this project.

Ok, so here's my issue:
I need to dynamicly place text on a "Certificate of Completion" jpg template. ie: Course name, user name, etc. I've got it working just fine.

However, what I run up against is centering this text in the middle of the graphic left to right. Initially I'm just using the Serrif font by default.

I've tried:
1) Create a transparent gif (17x16px - the size of text "G") and place text in it with addtext(), then Watermark it on the main graphic. But the graphic doesn't stretch. I figured it wouldn't work. The benifit of this would be that I could get info on the new transparent graphic and center it by the resulting size. Alas, it not that easy.

I thought about:
1) Measure each letter from A..Z and a..z then parse the input string and add up the resulting size in px, then do math to place it centered, this seemed like a lot of work. So I figured I'd post here prior to doing that.

Thoughts? Clear as mud?

Thanks for your time,

BN

RE: Placing Centered Text on a Graphic
Posted Thursday, September 20, 2007 at {ts '2018-12-15 16:27:00'}

Some pretty heavy traffic on this thread.. Wink

Well, I basicly solved it by measuring each character and storing those in a struct. Then I looped over each letter of the string, got the width and added them all up. Then did the math to center the text on the graphic. It was a bit time consuming to get the font/letter default Serif widths, but it works great.

BN

RE: Placing Centered Text on a Graphic
Posted Sunday, September 23, 2007 at {ts '2018-12-15 11:00:00'}

Cool. That's as good as any solution I might've come up with Smile

RE: Placing Centered Text on a Graphic
Posted Monday, February 16, 2009 at {ts '2018-12-15 15:46:00'}

I was able to come up with a solution to the centered text issue.

I modified the cffunction "addText". Here is a breakdown of what I did:
1. added the cfargument "Centered" (bit)
2. added a small if statement that if centered is desired, it calculates the metrics of the text and divides the width by 2. Then it takes the width of the image and divides by 2. Then I re-create the x coordinates by subtracting the halfed width of the image by the halved width of the text.

Here is the code for the function:

<cffunction name="addText" access="public" output="true" returntype="struct" hint="Add text to an image.">
   <cfargument name="objImage" required="yes" type="Any">
   <cfargument name="inputFile" required="yes" type="string">
   <cfargument name="outputFile" required="yes" type="string">
   <cfargument name="x" required="yes" type="numeric">
   <cfargument name="y" required="yes" type="numeric">
   <cfargument name="fontDetails" required="yes" type="struct">
   <cfargument name="content" required="yes" type="String">
   <cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
<cfargument name="centered" required="no" type="any" default="no">

   <cfset var retVal = StructNew()>
   <cfset var loadImage = StructNew()>
   <cfset var img = "">
   <cfset var saveImage = StructNew()>
   <cfset var g2d = "">
   <cfset var bgImage = "">
   <cfset var fontImage = "">
   <cfset var overlayImage = "">
   <cfset var Color = "">
   <cfset var font = "">
   <cfset var font_stream = "">
   <cfset var ac = "">
   <cfset var rgb = "">
   
   <cfset retVal.errorCode = 0>
   <cfset retVal.errorMessage = "">

   <cfparam name="arguments.fontDetails.size" default="12">
   <cfparam name="arguments.fontDetails.color" default="black">
   <cfparam name="arguments.fontDetails.fontFile" default="">
   <cfparam name="arguments.fontDetails.fontName" default="serif">

   <cfif arguments.fontDetails.fontFile neq "" and not fileExists(arguments.fontDetails.fontFile)>
      <cfset retVal = throw("The specified font file #Chr(34)##arguments.inputFile##Chr(34)# could not be found on the server.")>
      <cfreturn retVal>
   </cfif>
   <cftry>
      <cfset rgb = getRGB(arguments.fontDetails.color)>
      <cfcatch type="any">
         <cfset retVal = throw("Invalid color #Chr(34)##arguments.fontDetails.color##Chr(34)#")>
         <cfreturn retVal>
      </cfcatch>
   </cftry>
   <cfif inputFile neq "">
      <cfset loadImage = readImage(inputFile, "NO")>
      <cfif loadImage.errorCode is 0>
         <cfset img = loadImage.img>
      <cfelse>
         <cfset retVal = throw(loadImage.errorMessage)>
         <cfreturn retVal>
      </cfif>
   <cfelse>
      <cfset img = objImage>
   </cfif>
   <cfif img.getType() eq 0>
      <cfset img = convertImageObject(img,img.TYPE_3BYTE_BGR)>
   </cfif>
   <cfscript>
      // load objects
      bgImage = CreateObject("java", "java.awt.image.BufferedImage");
      fontImage = CreateObject("java", "java.awt.image.BufferedImage");
      overlayImage = CreateObject("java", "java.awt.image.BufferedImage");
      Color = CreateObject("java","java.awt.Color");
      font = createObject("java","java.awt.Font");
      font_stream = createObject("java","java.io.FileInputStream");
      ac = CreateObject("Java", "java.awt.AlphaComposite");
   
      // set up basic needs
      fontColor = Color.init(javacast("int", rgb.red), javacast("int", rgb.green), javacast("int", rgb.blue));

      if (fontDetails.fontFile neq "")
      {
         font_stream.init(arguments.fontDetails.fontFile);
         font = font.createFont(font.TRUETYPE_FONT, font_stream);
         font = font.deriveFont(javacast("float",arguments.fontDetails.size));
      } else {
         font.init(fontDetails.fontName, evaluate(fontDetails.style), fontDetails.size);
      }
      // get font metrics using a 1x1 bufferedImage
      fontImage.init(1,1,img.getType());
      g2 = fontImage.createGraphics();
      g2.setRenderingHints(getRenderingHints());
      fc = g2.getFontRenderContext();
      bounds = font.getStringBounds(content,fc);
      
      //DAVE Added 2009_02_16
      if (centered IS 1) {
         textWidth = fontBounds.getWidth();
         imageWidth = img.width;
         x = int((imageWidth/2) - (textWidth/2));
      }
      
      g2 = img.createGraphics();
      g2.setRenderingHints(getRenderingHints());
      g2.setFont(font);
      g2.setColor(fontColor);
      // in case you want to change the alpha
      // g2.setComposite(ac.getInstance(ac.SRC_OVER, 0.50));

      // the location (arguments.fontDetails.size+y) doesn't really work
      // the way I want it to.
      g2.drawString(content,javacast("int",x),javacast("int",arguments.fontDetails.size+y));
      
      if (outputFile eq "")
      {
         retVal.img = img;
         return retVal;
      } else {
         saveImage = writeImage(outputFile, img, jpegCompression);
         if (saveImage.errorCode gt 0)
         {
            return saveImage;
         } else {
            return retVal;
         }
      }
   </cfscript>
</cffunction>

RE: Placing Centered Text on a Graphic
Posted Monday, February 16, 2009 at {ts '2018-12-15 17:00:00'}

Found a typo and cleaned up the code a bit:

Here is the function again:

<cffunction name="addText" access="public" output="true" returntype="struct" hint="Add text to an image.">
   <cfargument name="objImage" required="yes" type="Any">
   <cfargument name="inputFile" required="yes" type="string">
   <cfargument name="outputFile" required="yes" type="string">
   <cfargument name="x" required="yes" type="numeric">
   <cfargument name="y" required="yes" type="numeric">
   <cfargument name="fontDetails" required="yes" type="struct">
   <cfargument name="content" required="yes" type="String">
   
   <!--- DAVE ADDED 2009_02_16 --->
<cfargument name="centered" required="no" type="boolean" default="0">

<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">

   <cfset var retVal = StructNew()>
   <cfset var loadImage = StructNew()>
   <cfset var img = "">
   <cfset var saveImage = StructNew()>
   <cfset var g2d = "">
   <cfset var bgImage = "">
   <cfset var fontImage = "">
   <cfset var overlayImage = "">
   <cfset var Color = "">
   <cfset var font = "">
   <cfset var font_stream = "">
   <cfset var ac = "">
   <cfset var rgb = "">
   
   <cfset retVal.errorCode = 0>
   <cfset retVal.errorMessage = "">

   <cfparam name="arguments.fontDetails.size" default="12">
   <cfparam name="arguments.fontDetails.color" default="black">
   <cfparam name="arguments.fontDetails.fontFile" default="">
   <cfparam name="arguments.fontDetails.fontName" default="serif">

   <cfif arguments.fontDetails.fontFile neq "" and not fileExists(arguments.fontDetails.fontFile)>
      <cfset retVal = throw("The specified font file #Chr(34)##arguments.inputFile##Chr(34)# could not be found on the server.")>
      <cfreturn retVal>
   </cfif>
   <cftry>
      <cfset rgb = getRGB(arguments.fontDetails.color)>
      <cfcatch type="any">
         <cfset retVal = throw("Invalid color #Chr(34)##arguments.fontDetails.color##Chr(34)#")>
         <cfreturn retVal>
      </cfcatch>
   </cftry>
   <cfif inputFile neq "">
      <cfset loadImage = readImage(inputFile, "NO")>
      <cfif loadImage.errorCode is 0>
         <cfset img = loadImage.img>
      <cfelse>
         <cfset retVal = throw(loadImage.errorMessage)>
         <cfreturn retVal>
      </cfif>
   <cfelse>
      <cfset img = objImage>
   </cfif>
   <cfif img.getType() eq 0>
      <cfset img = convertImageObject(img,img.TYPE_3BYTE_BGR)>
   </cfif>
   <cfscript>
      // load objects
      bgImage = CreateObject("java", "java.awt.image.BufferedImage");
      fontImage = CreateObject("java", "java.awt.image.BufferedImage");
      overlayImage = CreateObject("java", "java.awt.image.BufferedImage");
      Color = CreateObject("java","java.awt.Color");
      font = createObject("java","java.awt.Font");
      font_stream = createObject("java","java.io.FileInputStream");
      ac = CreateObject("Java", "java.awt.AlphaComposite");
   
      // set up basic needs
      fontColor = Color.init(javacast("int", rgb.red), javacast("int", rgb.green), javacast("int", rgb.blue));

      if (fontDetails.fontFile neq "")
      {
         font_stream.init(arguments.fontDetails.fontFile);
         font = font.createFont(font.TRUETYPE_FONT, font_stream);
         font = font.deriveFont(javacast("float",arguments.fontDetails.size));
      } else {
         font.init(fontDetails.fontName, evaluate(fontDetails.style), fontDetails.size);
      }
      // get font metrics using a 1x1 bufferedImage
      fontImage.init(1,1,img.getType());
      g2 = fontImage.createGraphics();
      g2.setRenderingHints(getRenderingHints());
      fc = g2.getFontRenderContext();
      bounds = font.getStringBounds(content,fc);
      
      //DAVE Added 2009_02_16
      if (centered IS 1) {
         textWidth = bounds.getWidth();
         imageWidth = img.width;
         x = int((imageWidth/2) - (textWidth/2));
      }
      
      g2 = img.createGraphics();
      g2.setRenderingHints(getRenderingHints());
      g2.setFont(font);
      g2.setColor(fontColor);
      // in case you want to change the alpha
      // g2.setComposite(ac.getInstance(ac.SRC_OVER, 0.50));

      // the location (arguments.fontDetails.size+y) doesn't really work (DAVE Removed arguments.fontDetails.size+y)
      // the way I want it to.
      g2.drawString(content,javacast("int",x),javacast("int",y));
      
      if (outputFile eq "")
      {
         retVal.img = img;
         
         // DAVE added for testing
         retVal.x = x;
         retVal.y = y;
         retVal.z = content;
         retVal.centered = centered;
         //end of DAVE mods.
         
         return retVal;
      } else {
         saveImage = writeImage(outputFile, img, jpegCompression);
         if (saveImage.errorCode gt 0)
         {
            return saveImage;
         } else {
            return retVal;
         }
      }
   </cfscript>
</cffunction>

New Topic Reply Subscription Options   Previous Page  Page: 1   Previous Page
Subscription Options
Subscription options are available after you log in.

There are 25 active user sessions right now.