Posted in

IndexedDB and Saving Images in JavaScript

Question: How to save an image from a canvas to IndexedDB using vanilla JavaScript?

Here’s a complete example of how to save an image from a canvas to IndexedDB using vanilla JavaScript.

Step 1: HTML Structure

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Save Canvas to IndexedDB</title>
</head>
<body>
    <canvas id="myCanvas" width="300" height="300"></canvas>
    <button id="saveButton">Save Image to IndexedDB</button>
    <div id="savedImage"></div>

    <script src="script.js"></script>
</body>
</html>

Step 2: JavaScript Code (script.js)

// Open (or create) the IndexedDB database
let db;
const request = indexedDB.open('imageDatabase', 1);

// Setup the database and object store
request.onupgradeneeded = function (event) {
    db = event.target.result;
    db.createObjectStore('images', { keyPath: 'id', autoIncrement: true });
};

request.onsuccess = function (event) {
    db = event.target.result;
};

request.onerror = function (event) {
    console.error('Database error:', event.target.error);
};

// Draw something on the canvas
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 200, 200);

// Save image from canvas to IndexedDB
document.getElementById('saveButton').addEventListener('click', function () {
    canvas.toBlob(function (blob) {
        const transaction = db.transaction(['images'], 'readwrite');
        const store = transaction.objectStore('images');
        const request = store.add({ image: blob });

        request.onsuccess = function () {
            console.log('Image saved successfully!');
            displaySavedImage();
        };

        request.onerror = function (event) {
            console.error('Error saving image:', event.target.error);
        };
    }, 'image/png');
});

// Retrieve and display saved image
function displaySavedImage() {
    const transaction = db.transaction(['images'], 'readonly');
    const store = transaction.objectStore('images');
    const request = store.get(1); // Assuming you're fetching the first image saved

    request.onsuccess = function (event) {
        const record = event.target.result;
        if (record) {
            const imgURL = URL.createObjectURL(record.image);
            const img = document.createElement('img');
            img.src = imgURL;
            document.getElementById('savedImage').appendChild(img);
        } else {
            console.log('No image found in the database.');
        }
    };

    request.onerror = function (event) {
        console.error('Error retrieving image:', event.target.error);
    };
}

Explanation

  • IndexedDB Setup: The code sets up an IndexedDB named imageDatabase with an object store called images where images are stored as Blob objects.
  • Canvas Drawing: The canvas is drawn with a simple blue rectangle.
  • Saving the Image: The toBlob method is used to convert the canvas content to a Blob, which is then saved to IndexedDB.
  • Displaying Saved Image: The image is retrieved from IndexedDB and displayed by creating a URL for the Blob.

Question: How to save a Blob from a Data URL?

Converting a Data URL to a Blob

// Function to convert a Data URL to a Blob
function dataURLtoBlob(dataURL) {
    // Split the data URL into the header and the Base64-encoded content
    const [header, base64String] = dataURL.split(',');
    
    // Decode the Base64 string into a byte array
    const binaryString = atob(base64String);
    const len = binaryString.length;
    const byteArray = new Uint8Array(len);
    
    // Convert the binary string to a byte array
    for (let i = 0; i < len; i++) {
        byteArray[i] = binaryString.charCodeAt(i);
    }
    
    // Determine the MIME type from the header (e.g., 'image/png')
    const mimeString = header.split(':')[1].split(';')[0];
    
    // Create a Blob from the byte array
    return new Blob([byteArray], { type: mimeString });
}

// Example usage: Convert a Data URL to a Blob and save to IndexedDB
const dataURL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...'; // Your Data URL here
const blob = dataURLtoBlob(dataURL);

// Save the Blob to IndexedDB
let db;
const request = indexedDB.open('imageDatabase', 1);

request.onupgradeneeded = function (event) {
    db = event.target.result;
    db.createObjectStore('images', { keyPath: 'id', autoIncrement: true });
};

request.onsuccess = function (event) {
    db = event.target.result;
    saveBlobToIndexedDB(blob);
};

function saveBlobToIndexedDB(blob) {
    const transaction = db.transaction(['images'], 'readwrite');
    const store = transaction.objectStore('images');
    const request = store.add({ image: blob });

    request.onsuccess = function () {
        console.log('Blob saved successfully!');
    };

    request.onerror = function (event) {
        console.error('Error saving blob:', event.target.error);
    };
}

Explanation

  • Converts a data URL to a Blob by decoding the Base64 data and creating a Blob from the binary data.
  • Saves the Blob to IndexedDB for efficient storage.

Question: Does IndexedDB access require any permissions from the user?

  • No Permission Required: IndexedDB can be accessed without explicit user permissions.
  • Secure Context: Must be accessed in a secure context (HTTPS).
  • Quota Limits: Browsers enforce quota limits; exceeding them might prompt for more space or clear data.
  • Best Practice: Inform users when significant data is being saved.

Thank you for using this guide for your IndexedDB and JavaScript development needs! If you have more questions, feel free to ask.