This repository has been archived by the owner on Dec 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlqip.js
122 lines (108 loc) · 4 KB
/
lqip.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import { canvasRGB } from 'stackblur-canvas';
const lqipHeader = window.GaussholderHeader;
const lqip = function( img, lqipData ) {
const lqipWidth = parseInt( lqipData[ 1 ], 10 );
const lqipHeight = parseInt( lqipData[ 2 ], 10 );
let lqipImg;
let canvas;
let ctx;
let imgLoaded = false;
const createLqip = function() {
const arrayBufferToBase64 = function( buffer ) {
let binary = '';
const bytes = new Uint8Array( buffer );
const len = bytes.byteLength;
for ( let i = 0; i < len; i++ ) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
};
const reconstituteImage = function() {
const lqipPart = lqipData[ 0 ];
const lqipTotal = atob( lqipHeader.header ) + atob( lqipPart );
const bytes = new Uint8Array( lqipTotal.length );
for ( let i = 0; i < lqipTotal.length; i++ ) {
bytes[ i ] = lqipTotal.charCodeAt( i );
}
// Poke the bits.
/* eslint-disable no-bitwise */
bytes[ lqipHeader.height_offset ] = ( ( lqipHeight >> 8 ) & 0xFF );
bytes[ lqipHeader.height_offset + 1 ] = ( lqipHeight & 0xFF );
bytes[ lqipHeader.length_offset ] = ( ( lqipWidth >> 8 ) & 0xFF );
bytes[ lqipHeader.length_offset + 1 ] = ( lqipWidth & 0xFF );
/* eslint-enable no-bitwise */
// Back to a full JPEG now.
return arrayBufferToBase64( bytes );
};
const onloadLqip = function() {
// Render only in viewport.
if ( lqipImg ) {
lqipImg.removeEventListener( 'load', onloadLqip );
lqipImg.removeEventListener( 'error', onloadLqip );
}
if ( ! imgLoaded ) {
img.style.backgroundRepeat = 'no-repeat';
img.style.backgroundSize = 'cover';
if ( canvas ) {
ctx.drawImage( lqipImg, 0, 0, lqipWidth, lqipHeight );
canvasRGB( canvas, 0, 0, lqipWidth, lqipHeight, 1 );
img.style.backgroundImage = 'url("' + canvas.toDataURL() + '")';
img.classList.add( 'guessholder-loaded' );
}
// Use modern toBlob? toDataURL has performance issues.
// if ( canvas.toBlob ) {
// canvas.toBlob( function( blob ) {
// const url = window.URL.createObjectURL( blob );
// // window.URL.revokeObjectURL( url );
// img.style.backgroundImage = 'url("' + url + '")';
// } );
// }
}
img.classList.remove( 'guessholder-loading' );
};
// Use original LQIP sizes and background-size=cover for performance reasons.
canvas = document.createElement( 'canvas' );
canvas.width = lqipWidth;
canvas.height = lqipHeight;
ctx = canvas.getContext( '2d', { alpha: false } );
// Ensure smoothing is off
// ctx.mozImageSmoothingEnabled = false;
// ctx.webkitImageSmoothingEnabled = false;
// ctx.msImageSmoothingEnabled = false;
// ctx.imageSmoothingEnabled = false;
lqipImg = new Image();
lqipImg.addEventListener( 'load', onloadLqip );
lqipImg.addEventListener( 'error', onloadLqip );
lqipImg.src = 'data:image/jpg;base64,' + reconstituteImage();
};
const remove = function() {
lqipImg = null;
ctx = null;
canvas = null;
img.style.backgroundImage = '';
img.style.backgroundRepeat = '';
img.style.backgroundSize = '';
img.classList.add( 'guessholder-removed' );
img.classList.remove( 'guessholder-loading' );
img.classList.remove( 'guessholder-loaded' );
if ( img.style.length == 0 ) {
img.removeAttribute( 'style' );
}
};
const lazyloaded = function() {
img.removeEventListener( 'lazyloaded', lazyloaded );
imgLoaded = true;
setTimeout( remove, 800 );
};
createLqip();
// Render original image only in viewport.
img.setAttribute( 'data-expand', -1 );
img.addEventListener( 'lazyloaded', lazyloaded );
};
window.addEventListener( 'lazybeforeunveil', function( e ) {
const img = e.target;
const lqipData = img.getAttribute( 'data-gaussholder' );
if ( lqipData ) {
lqip( img, lqipData.split( ',' ) );
}
} );