diff --git a/src/Plugin/Field/FieldFormatter/TextimageTextFieldFormatter.php b/src/Plugin/Field/FieldFormatter/TextimageTextFieldFormatter.php
index 9caefcf..d459f86 100644
--- a/src/Plugin/Field/FieldFormatter/TextimageTextFieldFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/TextimageTextFieldFormatter.php
@@ -277,7 +277,7 @@ class TextimageTextFieldFormatter extends FormatterBase implements ContainerFact
     $field = $instance->getFieldStorageDefinition();
     $token_data = [$instance->getTargetEntityTypeId() => $items->getEntity()];
 
-    // Get sanitized text strings from the text field.
+    // Get text strings from the text field.
     $text = $this->textimageFactory->getTextFieldText($items);
 
     // Get alt and title text from the formatter settings, and resolve tokens.
diff --git a/src/Tests/TextimageApiTest.php b/src/Tests/TextimageApiTest.php
index 18e6fa5..6a54de8 100644
--- a/src/Tests/TextimageApiTest.php
+++ b/src/Tests/TextimageApiTest.php
@@ -216,6 +216,50 @@ class TextimageApiTest extends TextimageTestBase {
     $this->assertEqual('image/png', $image->getMimeType());
     $image_file_extension = pathinfo($textimage->getUri(), PATHINFO_EXTENSION);
     $this->assertEqual('png', $image_file_extension);
+
+    // Check text altering via the effect's alter hook.
+    $effects = [];
+    $effects[] = [
+      'id' => 'image_effects_text_overlay',
+      'data' => [
+        'text' => [
+          'strip_tags' => TRUE,
+          'decode_entities' => TRUE,
+          'maximum_chars' => 12,
+          'excess_chars_text' => ' [more]',
+          'case_format' => 'upper',
+        ],
+        'text_string' => 'Test preview',
+      ],
+    ];
+    $textimage = $this->textimageFactory->get();
+    $textimage
+      ->setEffects($effects)
+      ->process('the quick brown fox jumps over the lazy dog');
+    $this->assertEqual(['THE QUICK BR [more]'], $textimage->getText());
+    $effects = [];
+    $effects[] = [
+      'id' => 'image_effects_text_overlay',
+      'data' => [
+        'text' => [
+          'strip_tags' => TRUE,
+          'decode_entities' => TRUE,
+          'case_format' => '',
+          'maximum_chars' => NULL,
+        ],
+        'text_string' => 'Test preview',
+      ],
+    ];
+    $textimage = $this->textimageFactory->get();
+    $textimage
+      ->setEffects($effects)
+      ->process('<p>Para1</p><!-- Comment --> Para2');
+    $this->assertEqual(['Para1 Para2'], $textimage->getText());
+    $textimage = $this->textimageFactory->get();
+    $textimage
+      ->setEffects($effects)
+      ->process('&quot;Title&quot; One &hellip;');
+    $this->assertEqual(['"Title" One …'], $textimage->getText());
   }
 
   /**
diff --git a/src/Tests/TextimageFieldFormatterTest.php b/src/Tests/TextimageFieldFormatterTest.php
index 6687dd1..7f4c4a5 100644
--- a/src/Tests/TextimageFieldFormatterTest.php
+++ b/src/Tests/TextimageFieldFormatterTest.php
@@ -35,8 +35,8 @@ class TextimageFieldFormatterTest extends TextimageTestBase {
     $this->createTextField($field_name, 'article');
 
     // Create a new node.
-    $field_value = $this->randomMachineName(20);
-    $nid = $this->createTextimageNode('text', $field_name, $field_value, 'article');
+    $field_value = '<p>Para1</p><!-- Comment --> Para2  &quot;Title&quot; One &hellip;';
+    $nid = $this->createTextimageNode('text', $field_name, $field_value, 'article', 'Overly test');
     $node = Node::load($nid);
 
     // Get Textimage URL.
@@ -60,7 +60,7 @@ class TextimageFieldFormatterTest extends TextimageTestBase {
     $elements = $this->cssSelect("img[src='$rel_url']");
     $this->assertTrue(!empty($elements), 'Unlinked Textimage displaying on full node view.');
     $this->assertEqual($elements[0]['alt']->__toString(), 'Alternate text: ' . $field_value);
-    $this->assertEqual($elements[0]['title']->__toString(), 'Title: ' . $field_value);
+    $this->assertEqual($elements[0]['title']->__toString(), 'Title: Overly test');
 
     // Test the textimage formatter - linked to content.
     $display_options['settings']['image_link'] = 'content';
@@ -125,7 +125,7 @@ class TextimageFieldFormatterTest extends TextimageTestBase {
     for ($i = 0; $i < 4; $i++) {
       $field_value[] = $this->randomMachineName(20);
     }
-    $nid = $this->createTextimageNode('text', $field_name, $field_value, 'article');
+    $nid = $this->createTextimageNode('text', $field_name, $field_value, 'article', 'Test Title');
     $node = Node::load($nid);
 
     // Test the textimage formatter - one image.
@@ -149,7 +149,7 @@ class TextimageFieldFormatterTest extends TextimageTestBase {
     $this->assertEqual(1, count($elements));
     $this->assertEqual($rel_url, $elements[0]['src']->__toString());
     $this->assertEqual('Alternate text: ' . $field_value[0], $elements[0]['alt']->__toString());
-    $this->assertEqual('Title: ' . $field_value[0], $elements[0]['title']->__toString());
+    $this->assertEqual('Title: Test Title', $elements[0]['title']->__toString());
 
     // Test the textimage formatter - multiple images.
     $display = entity_get_display('node', $node->getType(), 'default');
@@ -192,7 +192,7 @@ class TextimageFieldFormatterTest extends TextimageTestBase {
     // Create a new node.
     // Get image 'image-1.png'.
     $field_value = $this->drupalGetTestFiles('image', 39325)[0];
-    $nid = $this->createTextimageNode('image', $field_name, $field_value, 'article');
+    $nid = $this->createTextimageNode('image', $field_name, $field_value, 'article', $this->randomMachineName());
     $node = Node::load($nid);
     $node_title = $node->get('title')[0]->get('value')->getValue();
 
@@ -302,7 +302,7 @@ class TextimageFieldFormatterTest extends TextimageTestBase {
 
     // Create a new node.
     $field_value = 'test for caching';
-    $nid = $this->createTextimageNode('text', $field_name, $field_value, 'article');
+    $nid = $this->createTextimageNode('text', $field_name, $field_value, 'article', 'test');
     $node = Node::load($nid);
 
     // Set textimage formatter - no link.
@@ -397,15 +397,17 @@ class TextimageFieldFormatterTest extends TextimageTestBase {
    *   Value of the field formatted by Textimage.
    * @param string $bundle
    *   The type of node to create.
+   * @param string $node_title
+   *   The title of node to create.
    */
-  protected function createTextimageNode($field_type, $field_name, $field_value, $bundle) {
+  protected function createTextimageNode($field_type, $field_name, $field_value, $bundle, $node_title) {
     switch ($field_type) {
       case 'text':
         if (!is_array($field_value)) {
           $field_value = [$field_value];
         }
         $edit = [
-          'title[0][value]' => $field_value[0],
+          'title[0][value]' => $node_title,
           'body[0][value]' => $field_value[0],
         ];
         for ($i = 0; $i < count($field_value); $i++) {
@@ -417,7 +419,7 @@ class TextimageFieldFormatterTest extends TextimageTestBase {
 
       case 'image':
         $edit = [
-          'title[0][value]' => $this->randomMachineName(),
+          'title[0][value]' => $node_title,
         ];
         $edit['files[' . $field_name . '_0]'] = drupal_realpath($field_value->uri);
         $this->drupalPostForm('node/add/' . $bundle, $edit, t('Save'));
diff --git a/src/Textimage.php b/src/Textimage.php
index abb5a7c..dfb449b 100644
--- a/src/Textimage.php
+++ b/src/Textimage.php
@@ -520,14 +520,18 @@ class Textimage implements TextimageInterface {
     $this->tokenData['file'] = isset($this->tokenData['file']) ? $this->tokenData['file'] : $this->sourceImageFile;
     foreach ($default_text as $uuid => $default_text_item) {
       $text_item = array_shift($text);
+      $effect_instance = $this->imageEffectManager->createInstance($this->effects[$uuid]['id']);
+      $effect_instance->setConfiguration($this->effects[$uuid]);
       if ($text_item) {
         // Replace any tokens in text with run-time values.
         $text_item = ($text_item == '[textimage:default]') ? $default_text_item : $text_item;
-        $processed_text[$uuid] = $this->factory->processTextString($text_item, $this->effects[$uuid]['data']['text']['case_format'], $this->tokenData, $this->bubbleableMetadata);
+        $processed_text[$uuid] = $this->factory->processTextString($text_item, NULL, $this->tokenData, $this->bubbleableMetadata);
       }
       else {
-        $processed_text[$uuid] = $this->factory->processTextString($default_text_item, $this->effects[$uuid]['data']['text']['case_format'], $this->tokenData, $this->bubbleableMetadata);
+        $processed_text[$uuid] = $this->factory->processTextString($default_text_item, NULL, $this->tokenData, $this->bubbleableMetadata);
       }
+      // Let text be altered by the effect's alter hook.
+      $processed_text[$uuid] = $effect_instance->getAlteredText($processed_text[$uuid]);
     }
     $this->text = $processed_text;
 
diff --git a/src/TextimageFactory.php b/src/TextimageFactory.php
index d43ccfc..2173e6b 100644
--- a/src/TextimageFactory.php
+++ b/src/TextimageFactory.php
@@ -122,26 +122,7 @@ class TextimageFactory implements TextimageFactoryInterface {
   public function processTextString($text, $case_format, array $token_data = [], BubbleableMetadata $bubbleable_metadata = NULL) {
     // Replace any tokens in text with run-time values.
     $token_data['user'] = !empty($token_data['user']) ? $token_data['user'] : $this->userStorage->load($this->currentUser->id());
-    $text = $this->token->replace($text, $token_data, [], $bubbleable_metadata);
-
-    // Convert case, if requested.
-    switch ($case_format) {
-      case 'upper':
-        return Unicode::strtoupper($text);
-
-      case 'lower':
-        return Unicode::strtolower($text);
-
-      case 'ucfirst':
-        return Unicode::ucfirst($text);
-
-      case 'ucwords':
-        return Unicode::ucwords($text);
-
-      default:
-        return $text;
-
-    }
+    return $this->token->replace($text, $token_data, [], $bubbleable_metadata);
   }
 
   /**
@@ -532,7 +513,7 @@ class TextimageFactory implements TextimageFactoryInterface {
     $text = [];
     foreach ($items as $item) {
       $value = $item->getValue();
-      $text[] = !empty($value['value']) ? strip_tags($value['value']) : '';
+      $text[] = !empty($value['value']) ? $value['value'] : '';
     }
     return $text;
   }
diff --git a/src/TextimageFactoryInterface.php b/src/TextimageFactoryInterface.php
index f81fde6..d122c45 100644
--- a/src/TextimageFactoryInterface.php
+++ b/src/TextimageFactoryInterface.php
@@ -48,6 +48,8 @@ interface TextimageFactoryInterface {
    *
    * @return string
    *   The processed text string.
+   *
+   * @todo The $case_format parameter is deprecated, remove in a future major.
    */
   public function processTextString($text, $case_format, array $token_data = [], BubbleableMetadata $bubbleable_metadata = NULL);
 
@@ -126,9 +128,6 @@ interface TextimageFactoryInterface {
   /**
    * Retrieves text from a Text field.
    *
-   * Text gets sanitized for use within Textimage: HTML tags are
-   * stripped.
-   *
    * @param Drupal\Core\Field\FieldItemListInterface $items
    *   Field items.
    *
