0

I am trying to get an image from the private folder to display on a printer-friendly Twig template page. The private folder is inaccessible to browsers and the only display method I know of is to load the image and convert it to Base64 and pass the Base64 characters into the 'src' attribute of an 'img' element.

My controller code looks something like this:

class PrinterFriendlyController extends ControllerBase {

  public function printerFriendly($text) {

    // Load image from private directory and convert to base64
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $image = $this->entityTypeManager
      ->getStorage('file')
      ->load($file_id);
    $image_path = PrivateStream::basePath() . '/images/' . $image->getFilename();
    $image_data = file_get_contents($image_path);
    $image_base64 = 'data:' . finfo_file($finfo, $image_path) . ';base64,' . base64_encode($image_data);

    $page = [
      // Definitely longer than 255 characters
      '#image_base64' => $image_base64,
      // This doesn't work either so it's not a character length issue
      //'#image_base64' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',
      '#text' => $text,
      '#theme' => 'printer_friendly',
    ];

    return $page;
  }
}

The template file looks something like this:

<div id="printer-friendly">
  <img src="{{ image_base64 }}" />
  <div id="text">{{ text }}</div>
</div>

The 'text' element contains custom text that is positioned over the 'img' element using CSS but is only included for context. It's not related to the problem.

The result that appears on Chrome Inspect is:

<img src="">

or

<img src(unknown)>

Either Drupal or Twig is blocking the Base64 image characters but I don't know which one is doing the blocking and I don't know how to prevent it from doing so.

2
  • How about if you fix data like your line commented //'#image_base64' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',. can the image display?
    – MrD
    Jun 22, 2021 at 4:49
  • No, it doesn't. I used that line to see if the issue is being caused by a character limit but it's not. Drupal is filtering out the Base64 string for some other reason.
    – user320691
    Jun 22, 2021 at 13:15

1 Answer 1

1

Maybe your problem come from function theme printer_friendly. If your define this funtion, you have to provide variables when define. If this function from contribute module you can use hook_preprocess_printer_friendly to add more variables before render in twig template.

4
  • It's a custom module with a Twig template. It has several text variables like '#text' that display when the page is rendered. Also, if I hard code the Base64 image in the template with something like '<img src="data:image/png;base64,iVBORw0KGg...">', the image displays correctly. It's only when I try to pass in a Base64 character string variable to the image 'src' attribute that either Drupal or Twig disallows it and makes it blank. I know the Base64 character string is being blocked but I don't know where, why or if there is a way to get around it. Thank you for your response.
    – user320691
    Jun 23, 2021 at 3:52
  • 1
    did you try {{ image_base64|raw }}
    – MrD
    Jun 23, 2021 at 4:07
  • Your answer is correct. I just didn't fully understand it the first time I read it. I did not remember to add the new variable 'image_base64' to 'hook_theme'. After I added it, it worked with the short Base64 red dot test string but, when the long 100+ kilobyte image Base64 string was passed in, a 'RuntimeException: Failed to start the session because headers have already been sent by...' was thrown so I had to trigger the 'page_cache_kill_switch' service. Thank you.
    – user320691
    Jun 23, 2021 at 15:54
  • @user320691 Why do you not using default url private file? and using hook_file_download to control. I think it's better for you.
    – MrD
    Jun 24, 2021 at 1:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.