You are here

protected function CaptchaImageResponse::printString in CAPTCHA 8

Helper function for drawing text on the image.

Parameters

resource $image: Link to image stream resource.

int $width: Suggested output image width.

int $height: Suggested input image width.

array $fonts: Array of fonts names and paths.

int $font_size: Suggested font size.

string $text: Text to be written on the image.

bool $rtl: RTL.

Return value

bool TRUE if image generation was successful, FALSE otherwise.

1 call to CaptchaImageResponse::printString()
CaptchaImageResponse::generateImage in image_captcha/src/Response/CaptchaImageResponse.php
Base function for generating a image CAPTCHA.

File

image_captcha/src/Response/CaptchaImageResponse.php, line 355

Class

CaptchaImageResponse
Response which is returned as the captcha for image_captcha.

Namespace

Drupal\image_captcha\Response

Code

protected function printString(&$image, $width, $height, array $fonts, $font_size, $text, $rtl = FALSE) {
  $characters = _image_captcha_utf8_split($text);
  $character_quantity = count($characters);
  $foreground_rgb = $this
    ->hexToRgb($this->config
    ->get('image_captcha_foreground_color'));
  $foreground_color = imagecolorallocate($image, $foreground_rgb[0], $foreground_rgb[1], $foreground_rgb[2]);

  // Precalculate the value ranges for color randomness.
  $foreground_randomness = $this->config
    ->get('image_captcha_foreground_color_randomness');
  $foreground_color_range = [];
  if ($foreground_randomness) {
    for ($i = 0; $i < 3; $i++) {
      $foreground_color_range[$i] = [
        max(0, $foreground_rgb[$i] - $foreground_randomness),
        min(255, $foreground_rgb[$i] + $foreground_randomness),
      ];
    }
  }

  // Set default text color.
  $color = $foreground_color;

  // The image is separated in different character cages, one for
  // each character that will be somewhere inside that cage.
  $ccage_width = $width / $character_quantity;
  $ccage_height = $height;
  foreach ($characters as $c => $character) {

    // Initial position of character: in the center of its cage.
    $center_x = ($c + 0.5) * $ccage_width;
    if ($rtl) {
      $center_x = $width - $center_x;
    }
    $center_y = 0.5 * $height;

    // Pick a random font from the list.
    $font = $fonts[array_rand($fonts)];
    $font = _image_captcha_get_font_uri($font);

    // Get character dimensions for TrueType fonts.
    if ($font != 'BUILTIN') {
      putenv('GDFONTPATH=' . realpath('.'));
      $bbox = imagettfbbox($font_size, 0, $this->fileSystem
        ->realpath($font), $character);

      // In very rare cases with some versions of the GD library, the x-value
      // of the left side of the bounding box as returned by the first call of
      // imagettfbbox is corrupt (value -2147483648 = 0x80000000).
      // The weird thing is that calling the function a second time
      // can be used as workaround.
      // This issue is discussed at http://drupal.org/node/349218.
      if ($bbox[2] < 0) {
        $bbox = imagettfbbox($font_size, 0, $this->fileSystem
          ->realpath($font), $character);
      }
    }
    else {
      $character_width = imagefontwidth(5);
      $character_height = imagefontheight(5);
      $bbox = [
        0,
        $character_height,
        $character_width,
        $character_height,
        $character_width,
        0,
        0,
        0,
      ];
    }

    // Random (but small) rotation of the character.
    // @todo add a setting for this?
    $angle = mt_rand(-10, 10);

    // Determine print position: at what coordinate should the character be
    // printed so that the bounding box would be nicely centered in the cage?
    $bb_center_x = 0.5 * ($bbox[0] + $bbox[2]);
    $bb_center_y = 0.5 * ($bbox[1] + $bbox[7]);
    $angle_cos = cos($angle * 3.1415 / 180);
    $angle_sin = sin($angle * 3.1415 / 180);
    $pos_x = $center_x - ($angle_cos * $bb_center_x + $angle_sin * $bb_center_y);
    $pos_y = $center_y - (-$angle_sin * $bb_center_x + $angle_cos * $bb_center_y);

    // Calculate available room to jitter: how much
    // can the character be moved. So that it stays inside its cage?
    $bb_width = $bbox[2] - $bbox[0];
    $bb_height = $bbox[1] - $bbox[7];
    $dev_x = 0.5 * max(0, $ccage_width - abs($angle_cos) * $bb_width - abs($angle_sin) * $bb_height);
    $dev_y = 0.5 * max(0, $ccage_height - abs($angle_cos) * $bb_height - abs($angle_sin) * $bb_width);

    // Add jitter to position.
    $pos_x = $pos_x + mt_rand(-$dev_x, $dev_x);
    $pos_y = $pos_y + mt_rand(-$dev_y, $dev_y);

    // Calculate text color in case of randomness.
    if ($foreground_randomness) {
      $color = imagecolorallocate($image, mt_rand($foreground_color_range[0][0], $foreground_color_range[0][1]), mt_rand($foreground_color_range[1][0], $foreground_color_range[1][1]), mt_rand($foreground_color_range[2][0], $foreground_color_range[2][1]));
    }

    // Draw character.
    if ($font == 'BUILTIN') {
      imagestring($image, 5, $pos_x, $pos_y, $character, $color);
    }
    else {
      imagettftext($image, $font_size, $angle, $pos_x, $pos_y, $color, $this->fileSystem
        ->realpath($font), $character);
    }
  }
  return TRUE;
}