Link to home
Start Free TrialLog in
Avatar of Mark Gilbert
Mark GilbertFlag for United States of America

asked on

Optimisation and modification of existing custom function

Greetings experts,

A while back I posted a question which was kindly answered by Roonaan:

https://www.experts-exchange.com/questions/21553032/Replace-characters-of-string-with-predesigned-images-font-retention-URGENT.html

The code looks like this:

<?php
$title = "This is some text";
$imageLocation = "images/characters/";

$letters = array("A",  "B",  "C",  "D",  "E",  "F",  "G",  "H",  "I",  "J",  "K",  "L",  "M",  "N",  "O",  "P",  "Q",  "R",  "S",  "T",  "U",  "V",  "W",  "X",  "Y",  "Z",  "a",  "b",  "c",  "d",  "e",  "f",  "g",  "h",  "i",  "j",  "k",  "l",  "m",  "n",  "o",  "p",  "q",  "r",  "s",  "t",  "u",  "v",  "w",  "x",  "y",  "z",  "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "&",   "@",      ":",     ",",    "!",           "#",    "\"",            "-",     ".",      "+",    "£",     "?",        ";",          "'");
$images  = array("ca", "cb", "cc", "cd", "ce", "cf", "cg", "ch", "ci", "cj", "ck", "cl", "cm", "cn", "co", "cp", "cq", "cr", "cs", "ct", "cu", "cv", "cw", "cx", "cy", "cz", "la", "lb", "lc", "ld", "le", "lf", "lg", "lh", "li", "lj", "lk", "ll", "lm", "ln", "lo", "lp", "lq", "lr", "ls", "lt", "lu", "lv", "lw", "lx", "ly", "lz", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "and", "atsign", "colon", "coma", "exclamation", "hash", "inverted-coma", "minus", "period", "plus", "pound", "question", "semi-colon", "semi-inverted-coma");

if(!function_exists('array_combine')) {
  function array_combine($keys, $values) {
    if(count($keys) != count($values)) return false;
    $result = array();
    foreach($keys as $index => $value)
      $result[$value] = $values[$index];
    return $result;
  }
}


function imageText($title, $letters, $images, $imageLocation) {
 
  $letterImages = array_combine($letters, $images);
 
  $new_title = '';
 
  for($i = 0, $s = strlen($title); $i < $s; $i++)
  {
    if(isset($letterImages[$title[$i]]))
      $new_title .= '<img src="'.$imageLocation.$letterImages[$title[$i]].'.gif" />';
    else
      $new_title .= $title[$i];
  }

  return $new_title;
}

echo imageText($title, $letters, $images, $imageLocation);

?>

This function works perfectly if I have 1 line of text.  However, the scope of the requirement has changed for a different project and what I now require is for the function to be intellegent enough to wrap the line to a predefined number of characters (taking whole words into consideration) and then force the images to start a new line.  For example, if I have a text string of "the quick brown fox jumps over the lazy dog watching the slinky cat basking in the sun on a mat" would look great as a one liner.  However, if I had a table which was restricted to 60 chars worth of images, the line would look like:

the quick brown fox jumps over the lazy dog watching the sli
nky cat basking in the sun on a mat

What I would like the function to do if possible is to take into consideration that slinky would be chopped in half, so perhaps by using div tags it would look like:

<div>the quick brown fox jumps over the lazy dog watching the</div>
<div>slinky cat basking in the sun on a mat</div>

And so on for each line that it comes across.  Of course, I had thought of doing a "line wrap" before running the function by actually putting <div></div> where necessary, but the function breaks as it wouldn't be able to find the characters < or > and it will interpret the characters div as images.  

If you have any questions please don't hesitate to post.

Thanks for your help.

Ingwa.
Avatar of JakobA
JakobA

How about this:

<?php
$title = "This is some text";
$imageLocation = "images/characters/";

$letters = array("A",  "B",  "C",  "D",  "E",  "F",  "G",  "H",  "I",  "J",  "K",  "L",  "M",  "N",  "O",  "P",  "Q",  "R",  "S",  "T",  "U",  "V",  "W",  "X",  "Y",  "Z",  "a",  "b",  "c",  "d",  "e",  "f",  "g",  "h",  "i",  "j",  "k",  "l",  "m",  "n",  "o",  "p",  "q",  "r",  "s",  "t",  "u",  "v",  "w",  "x",  "y",  "z",  "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "&",   "@",      ":",     ",",    "!",           "#",    "\"",            "-",     ".",      "+",    "£",     "?",        ";",          "'");

$images  = array("ca", "cb", "cc", "cd", "ce", "cf", "cg", "ch", "ci", "cj", "ck", "cl", "cm", "cn", "co", "cp", "cq", "cr", "cs", "ct", "cu", "cv", "cw", "cx", "cy", "cz", "la", "lb", "lc", "ld", "le", "lf", "lg", "lh", "li", "lj", "lk", "ll", "lm", "ln", "lo", "lp", "lq", "lr", "ls", "lt", "lu", "lv", "lw", "lx", "ly", "lz", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "and", "atsign", "colon", "coma", "exclamation", "hash", "inverted-coma", "minus", "period", "plus", "pound", "question", "semi-colon", "semi-inverted-coma");

$widths = array( /* here you list the individual widths (in pixels) of the images used
                    Alternately you could use GDlib to look at the imagefiles and read their
                    width directly. that is more flexible, but also costly in servertime to
                    do each time the script is activated. anyway, you may not have the GDlib
                    exptensions installed in your php
                 */ )

if(!function_exists('array_combine')) {
  function array_combine($keys, $values) {
    if(count($keys) != count($values)) return false;
    $result = array();
    foreach($keys as $index => $value)
      $result[$value] = $values[$index];
    return $result;
  }
}

if(!function_exists('array_findWidths')) {
  function array_findWidths($keys, $values) {
    if(count($keys) != count($values)) return false;
    $result = array();
    foreach($keys as $index => $value)
      $result[$value] = $values[$index];
    return $result;
  }
}


function imageText($title, $letters, $images, $imageLocation,
                   $maxLinewidthInPixels ) {                         //ADDED parameter
 
  $letterImages = array_combine($letters, $images);

  $letterWidths = array_findWidths( $letters, $widths );             //ADDED array
                 // make an array with the width of each letterimage.

  $guessed_char_width = 10;       // I am guesswork assingning a width of 10 to the
                                  // characters that do not have a letterimage

  $new_title = '';
  $titlearray = new array();                                         //ADDED array
                 // collects each line as it is finished
  $line_width = 0;
  $prev_blank = $line_width;   // (there is no previous blank yet)

  $prev_blank_char = strlen($new_title);  // this reference the nr of characters in the $new_title
 
  for($i = 0, $s = strlen($title); $i < $s; $i++)
  {
    if(isset($letterImages[$title[$i]]))
      $new_title .= '<img src="'.$imageLocation.$letterImages[$title[$i]].'.gif" />';
      $line_width += $letterWidths[$title[$i]];      
    else
      if( $title[$i] === ' ' ) {
          // if $line_width is currently greater than the maximum a linechange should
          // be inserted at the previous blank.
          if ( $line_width > $maxLinewidthInPixels ) {
              if ( $prev_blank == 0 ) {
                  // too bad, a single word is wider than the allocated width.
                  // nothing we can do about it, so just hope it dont look too bad.
              } else {
                  $titlearray[] = substr( $new_title, 0, $prev_blank_char );
                  $new_title = substr( $new_title, $prev_blank_char+1 );
                  $line_width -= ($prev_blank+$guessed_char_width);        
              }
          }
          $prev_blank = $line_width;
          $prev_blank_char = strlen($new_title);
      }
      $new_title .= $title[$i];
      $line_width += $guessed_char_width;
  }
  $titlearray[] = $new_title;                     // add the last line to the array
  $new_title = implode( "<br />", $titlearray );  // turn it into one long multiline string

  return $new_title;
}
?>

Note that you need to fill in values in the width array. I have no clue about the size of your images :-))
Avatar of Mark Gilbert

ASKER

Jakob, I can see the logic in your answer.  Thank you for taking the time to provide all the useful comments too.  I will be testing this code as soon as I get to the office tomorrow and will report on my findings.  It looks like some great scripting, hope you don't mind the wait :)
SOLUTION
Avatar of ed987
ed987

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Jakob, I've had a bash at your code in a test file and it looks like this:

<?php
$title = "This is some text that should span many lines and retain the width of the lines";
$imageLocation = "images/characters/";

$letters = array("A",  "B",  "C",  "D",  "E",  "F",  "G",  "H",  "I",  "J",  "K",  "L",  "M",  "N",  "O",  "P",  "Q",  "R",  "S",  "T",  "U",  "V",  "W",  "X",  "Y",  "Z",  "a",  "b",  "c",  "d",  "e",  "f",  "g",  "h",  "i",  "j",  "k",  "l",  "m",  "n",  "o",  "p",  "q",  "r",  "s",  "t",  "u",  "v",  "w",  "x",  "y",  "z",  "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "&",   "@",      ":",     ",",    "!",           "#",    "\"",            "-",     ".",      "+",    "£",     "?",        ";",          "'", "%", "/");
$images  = array("U/a", "U/b", "U/c", "U/d", "U/e", "U/f", "U/g", "U/h", "U/i", "U/j", "U/k", "U/l", "U/m", "U/n", "U/o", "U/p", "U/q", "U/r", "U/s", "U/t", "U/u", "U/v", "U/w", "U/x", "U/y", "U/z", "L/a", "L/b", "L/c", "L/d", "L/e", "L/f", "L/g", "L/h", "L/i", "L/j", "L/k", "L/l", "L/m", "L/n", "L/o", "L/p", "L/q", "L/r", "L/s", "L/t", "L/u", "L/v", "L/w", "L/x", "L/y", "L/z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "and", "atsign", "colon", "coma", "exclamation", "hash", "inverted-coma", "minus", "period", "plus", "pound", "question", "semi-colon", "semi-inverted-coma", "percent", "slash");


                        /* here you list the individual widths (in pixels) of the images used
                    Alternately you could use GDlib to look at the imagefiles and read their
                    width directly. that is more flexible, but also costly in servertime to
                    do each time the script is activated. anyway, you may not have the GDlib
                    exptensions installed in your php
                 */
$widths = array("15", "12", "13", "12", "11", "10", "14", "13", "4", "11", "14", "11", "16", "14", "14", "11", "15", "12", "13", "14", "13", "15", "21", "14", "15", "13", "11", "11", "10", "12", "11", "10", "13", "11", "4", "7", "11", "3", "18", "12", "11", "11", "11", "7", "11", "10", "10", "12", "16", "11", "12", "10", "7", "12", "12", "13", "12", "12", "12", "11", "11", "13", "15", "18", "4", "5", "4", "15", "6", "7", "5", "13", "12", "9", "4", "4", "15", "10");

if(!function_exists('array_combine')) {
  function array_combine($keys, $values) {
    if(count($keys) != count($values)) return false;
    $result = array();
    foreach($keys as $index => $value)
      $result[$value] = $values[$index];
    return $result;
  }
}

if(!function_exists('array_findWidths')) {
  function array_findWidths($keys, $values) {
    if(count($keys) != count($values)) return false;
    $result = array();
    foreach($keys as $index => $value)
      $result[$value] = $values[$index];
    return $result;
  }
}


function imageText($title, $letters, $images, $imageLocation,
                   $maxLinewidthInPixels ) {                         //ADDED parameter
 
  $letterImages = array_combine($letters, $images);

  $letterWidths = array_findWidths( $letters, $widths );             //ADDED array
                 // make an array with the width of each letterimage.

  $guessed_char_width = 10;       // I am guesswork assingning a width of 10 to the
                                  // characters that do not have a letterimage

  $new_title = '';
  $titlearray = new array();                                         //ADDED array       // Line 50 Gives error
                 // collects each line as it is finished
  $line_width = 0;
  $prev_blank = $line_width;   // (there is no previous blank yet)

  $prev_blank_char = strlen($new_title);  // this reference the nr of characters in the $new_title
 
  for($i = 0, $s = strlen($title); $i < $s; $i++)
  {
    if(isset($letterImages[$title[$i]]))
      $new_title .= '<img src="'.$imageLocation.$letterImages[$title[$i]].'.gif" />';
      $line_width += $letterWidths[$title[$i]];      
    else
      if( $title[$i] === ' ' ) {
          // if $line_width is currently greater than the maximum a linechange should
          // be inserted at the previous blank.
          if ( $line_width > $maxLinewidthInPixels ) {
              if ( $prev_blank == 0 ) {
                  // too bad, a single word is wider than the allocated width.
                  // nothing we can do about it, so just hope it dont look too bad.
              } else {
                  $titlearray[] = substr( $new_title, 0, $prev_blank_char );
                  $new_title = substr( $new_title, $prev_blank_char+1 );
                  $line_width -= ($prev_blank+$guessed_char_width);        
              }
          }
          $prev_blank = $line_width;
          $prev_blank_char = strlen($new_title);
      }
      $new_title .= $title[$i];
      $line_width += $guessed_char_width;
  }
  $titlearray[] = $new_title;                     // add the last line to the array
  $new_title = implode( "<br />", $titlearray );  // turn it into one long multiline string

  return $new_title;
}
?>

When I ran the script it said "Parse error: syntax error, unexpected T_ARRAY, expecting T_STRING or T_VARIABLE or '$' in /wwwroot/bondfitness/htdocs/test.php on line 50".  I've marked line 50 for you.  So I changed the line to read:

$titlearray = array();

And then got an error: "Parse error: syntax error, unexpected T_ELSE in /wwwroot/bondfitness/htdocs/test.php on line 62"

Unfortunately, there appear to be some if statements that don't have { or } but I wasn't 100% sure of the logic as to where they should be specifically terminated.
ed987, I would also like to thank you for your code contribution.  Looking at your code, it appears that it seperates each "word" with a span class.  Logic looks great.  I am in the process of testing your code and will report back to you as soon as I am done.  Many thanks again.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Jakob, I've put your code in and it now looks like this:

<?php
$title = "This is some text that should span many lines and retain the width of the lines";
$imageLocation = "images/characters/";

$letters = array("A",  "B",  "C",  "D",  "E",  "F",  "G",  "H",  "I",  "J",  "K",  "L",  "M",  "N",  "O",  "P",  "Q",  "R",  "S",  "T",  "U",  "V",  "W",  "X",  "Y",  "Z",  "a",  "b",  "c",  "d",  "e",  "f",  "g",  "h",  "i",  "j",  "k",  "l",  "m",  "n",  "o",  "p",  "q",  "r",  "s",  "t",  "u",  "v",  "w",  "x",  "y",  "z",  "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "&",   "@",      ":",     ",",    "!",           "#",    "\"",            "-",     ".",      "+",    "£",     "?",        ";",          "'", "%", "/");
$images  = array("U/a", "U/b", "U/c", "U/d", "U/e", "U/f", "U/g", "U/h", "U/i", "U/j", "U/k", "U/l", "U/m", "U/n", "U/o", "U/p", "U/q", "U/r", "U/s", "U/t", "U/u", "U/v", "U/w", "U/x", "U/y", "U/z", "L/a", "L/b", "L/c", "L/d", "L/e", "L/f", "L/g", "L/h", "L/i", "L/j", "L/k", "L/l", "L/m", "L/n", "L/o", "L/p", "L/q", "L/r", "L/s", "L/t", "L/u", "L/v", "L/w", "L/x", "L/y", "L/z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "and", "atsign", "colon", "coma", "exclamation", "hash", "inverted-coma", "minus", "period", "plus", "pound", "question", "semi-colon", "semi-inverted-coma", "percent", "slash");


                        /* here you list the individual widths (in pixels) of the images used
                    Alternately you could use GDlib to look at the imagefiles and read their
                    width directly. that is more flexible, but also costly in servertime to
                    do each time the script is activated. anyway, you may not have the GDlib
                    exptensions installed in your php
                 */
$widths = array("15", "12", "13", "12", "11", "10", "14", "13", "4", "11", "14", "11", "16", "14", "14", "11", "15", "12", "13", "14", "13", "15", "21", "14", "15", "13", "11", "11", "10", "12", "11", "10", "13", "11", "4", "7", "11", "3", "18", "12", "11", "11", "11", "7", "11", "10", "10", "12", "16", "11", "12", "10", "7", "12", "12", "13", "12", "12", "12", "11", "11", "13", "15", "18", "4", "5", "4", "15", "6", "7", "5", "13", "12", "9", "4", "4", "15", "10");

if(!function_exists('array_combine')) {
  function array_combine($keys, $values) {
    if(count($keys) != count($values)) return false;
    $result = array();
    foreach($keys as $index => $value)
      $result[$value] = $values[$index];
    return $result;
  }
}

if(!function_exists('array_findWidths')) {
  function array_findWidths($keys, $values) {
    if(count($keys) != count($values)) return false;
    $result = array();
    foreach($keys as $index => $value)
      $result[$value] = $values[$index];
    return $result;
  }
}


function imageText($title, $letters, $images, $imageLocation,
                   $maxLinewidthInPixels ) {                         //ADDED parameter
 
  $letterImages = array_combine($letters, $images);

  $letterWidths = array_findWidths( $letters, $widths );             //ADDED array
                 // make an array with the width of each letterimage.

  $guessed_char_width = 10;       // I am guesswork assingning a width of 10 to the
                                  // characters that do not have a letterimage

  $new_title = '';
  $titlearray = array();                                         //ADDED array
                 // collects each line as it is finished
  $line_width = 0;
  $prev_blank = $line_width;   // (there is no previous blank yet)

  $prev_blank_char = strlen($new_title);  // this reference the nr of characters in the $new_title
 
  for($i = 0, $s = strlen($title); $i < $s; $i++)
  {
    if(isset($letterImages[$title[$i]])) {                                                             // added start and end bracket (ending at else)
      $new_title .= '<img src="'.$imageLocation.$letterImages[$title[$i]].'.gif" />';
      $line_width += $letterWidths[$title[$i]];      
    } else {                                                                                                   // added start bracket for else-part
      if( $title[$i] === ' ' ) {
          // if $line_width is currently greater than the maximum a linechange should
          // be inserted at the previous blank.
          if ( $line_width > $maxLinewidthInPixels ) {
              if ( $prev_blank == 0 ) {
                  // too bad, a single word is wider than the allocated width.
                  // nothing we can do about it, so just hope it dont look too bad.
              } else {
                  $titlearray[] = substr( $new_title, 0, $prev_blank_char );
                  $new_title = substr( $new_title, $prev_blank_char+1 );
                  $line_width -= ($prev_blank+$guessed_char_width);        
              }
           }
           $prev_blank = $line_width;
           $prev_blank_char = strlen($new_title);
       }                                                           //ends     if( $title[$i] === ' ' )
       $new_title .= $title[$i];
       $line_width += $guessed_char_width;
    }                                                             //ends else-part of    if(isset($letterImages[$title[$i]]))
  }                                                               //ADDED }.  ends for loop
  $titlearray[] = $new_title;                     // add the last line to the array
  $new_title = implode( "<br />", $titlearray );  // turn it into one long multiline string

  return $new_title;
}
?>
<?php echo imageText($title, $letters, $images, $imageLocation, 200); ?>

It is now displaying the images without any errors, however there's no <br />'s being inserted into the page.  Not sure why, but thought you should know.
Oh Wait!  My bad.  Sorry.  The script does work, I changed 200 to 100 and it gave me a line break.  Thanks very much for fixing the script.
thanx :)