Score:0

Private file not being displayed on Twig template

ru flag

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.

MrD avatar
cn flag
MrD
How about if you fix data like your line commented `//'#image_base64' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',`. can the image display?
ru flag
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.
Score:1
cn flag
MrD

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.

ru flag
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.
MrD avatar
cn flag
MrD
did you try {{ image_base64|raw }}
ru flag
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.
MrD avatar
cn flag
MrD
@user320691 Why do you not using default url private file? and using hook_file_download to control. I think it's better for you.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.