Skip to content

Instantly share code, notes, and snippets.

@shanecowherd
Last active January 15, 2020 23:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shanecowherd/f063dc4e3710c438604331efee21d53d to your computer and use it in GitHub Desktop.
Save shanecowherd/f063dc4e3710c438604331efee21d53d to your computer and use it in GitHub Desktop.

Docker installation instructions

docker run --name heicconverter -v ~/Desktop/heicconverter:/root/heicconverter -p 8080:3000 -it ubuntu /bin/bash

Now you should be inside a docker container, run the following commends

cd ~/heicconverter
apt update; apt install nodejs npm libheif-examples -y

Now setup your express app

npm install express --save
npm init

Copy the rest of this file to your ~/Desktop/heicConverter folder and name it index.js


// Example usage: http://localhost:8080/?url=https://nokiatech.github.io/heif/content/images/autumn_1440x960.heic
// ?url= should be a url, if its URL encoded, it might break.
// The return response should be the image as a jpg with the corret mimetype.

// Temp folder to save images
const tempFolder = __dirname + '/' // Please include the trailling slash. '/root/heiclambda/'

// Lets you run another program and listen for its output.
const exec = require("child_process").exec
// Used to make external calls, we use this to download the heic file from the url the user gives us.
const request = require('request')
// Access the filesystem to save temporary files.
const fs = require('fs')
// Webserver
const express = require('express')

// Application
const app = express()
const port = 3000

app.get('/', (req, res) => {
    // Query string example.com?url=XXXXXX
    let url = req.query.url

    // If the url parameter is missing, lets return a 404 and tell the user how to use this service.
    if(url == undefined || url == '') {
        res.status(404).send('Include the file in the url. <br/>Example: url/?url=http://example.com/file.heic')
    }

    // We are going to save the file to the local filesystem.  Lets use the current time, it will help prevent collisions if multiple images are being called on the same instance at once.
    var currentTime = (new Date()).getTime()
    let heicLocation = tempFolder + currentTime + '.heic'
    let jpgLocation = tempFolder + currentTime + '.jpg'

    // Download the file from the url in the query parameter
    request
        .get(url)
        .on('end', ()=> {
            save(heicLocation, jpgLocation, (error) => {
                // If we run into an error converting the file, lets delete the temp file and let the user know.
                if (error) {
                    fs.unlinkSync(heicLocation)
                    res.status(500).send('Invalid .heic file')
                } else {
                    // File converted successfully, lets send the file to the user and delete the temp files.
                    
                    // Remove the heic file
                    fs.unlinkSync(heicLocation)

                    // Send the file to the user and delete the temp file once the user has received the file.
                    res.sendFile(jpgLocation, (error) => {

                        // Remove the jpg after we sent it to the user
                        fs.unlinkSync(jpgLocation)
                    })
                }
            })
        })
        // While we are downloading the file, stream it a file on the local filesystem.
        .pipe(fs.createWriteStream(heicLocation))
})

// Start the server and listen on a port.
app.listen(port, () => console.log(`Example app listening on port ${port}!`))

// Helper save function.  This runs the `heif-convert` application to actually convert the file.
// - heicLocation: is the file on disk that contains the file we want to convert.
// - jpgLocation: is the destination file on the disk that we want to write to.  This file will be replaced if it exists. (I believe)
// - callback: this is a function that will be called once the save operation is complete.
// - callback bool parameter: return `true` if there is an error. 
var save = (heicLocation, jpgLocation, callback) => {
    exec('/usr/bin/heif-convert ' + heicLocation + ' ' + jpgLocation, (error, stdout, stderr) => {
        if (error) {
            console.log(`error: ${error.message}`)
            callback(true)
            return
        }
        if (stderr) {
            console.log(`stderr: ${stderr}`)
            callback(true)
            return
        }
        console.log(`stdout: ${stdout}`)
        callback(false)
    });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment