Preview HEIC thumbnails when the frontend tools won’t

Since iPhone 8, a new image format has been around. HEIC files are unfortunately not supported by many frontend tools. While some solutions have been found, here’s how we solved it using a backend trick.

Prerequisites: pyheif, PIL

This post has an image featured from https://www.macworld.co.uk/feature/iphone/what-is-heic-3660408/. Use this link to find out more about HEIC/HEIF files if you want to learn more.

In frontend

Setup your frontend tool to fall back to a base64 img src. If the image uploaded is supported natively, use the base64 encoding provided by the frontend tool. Otherwise, make a backend call to convert the .HEIC file to jpg:

function convert_heic_to_jpeg(image_data, imageId, fallback) {
  if (image_data.type != "image/heic") {
    $(imageId).attr('src', fallback);
    return;
  }

  var fd = new FormData();
  var files = image_data;
  fd.append('file', files);

  $.ajax({
        url: '/ajax/convert-heic-to-jpeg/',  # whatever your backend URL for conversion is
        type: 'post',
        data: fd,
        contentType: false,
        processData: false,
        success: function(data) {
          $(imageId).attr('src', data['result']);
          return data;
        }
    });
}

In backend

Configure your URL in routes.py. Write a function that converts the HEIC to JPG, encodes the JPG data to base64 and return it as a JsonResponse.

import pyheif
import io

from PIL import Image

@csrf_exempt
@login_required
def convert_heic_to_jpeg(request):
    heic_img = pyheif.read(request.FILES['file'])
    pil_image = Image.frombytes(
        mode=heic_img.mode, size=heic_img.size, data=heic_img.data
    )

    output = io.BytesIO()
    pil_image.save(output, format="jpeg")
    output.seek(0)

    return JsonResponse({
        'result': "data:image/jpeg;base64," + base64.b64encode(
            output.getvalue()
        ).decode(),
    }, status=200)

Leave a Reply

Your email address will not be published. Required fields are marked *