-
Notifications
You must be signed in to change notification settings - Fork 50
/
dom-to-data-url.ts
57 lines (56 loc) · 2.18 KB
/
dom-to-data-url.ts
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
import type { Context } from '../context'
import type { Options } from '../options'
import { changeJpegDpi } from '../change-jpeg-dpi'
import { changePngDpi, detectPhysChunkFromDataUrl } from '../change-png-dpi'
import { orCreateContext } from '../create-context'
import { SUPPORT_ATOB, SUPPORT_BTOA } from '../utils'
import { domToCanvas } from './dom-to-canvas'
export async function domToDataUrl<T extends Node>(node: T, options?: Options): Promise<string>
export async function domToDataUrl<T extends Node>(context: Context<T>): Promise<string>
export async function domToDataUrl(node: any, options?: any): Promise<string> {
const context = await orCreateContext(node, options)
const { log, quality, type, dpi } = context
const canvas = await domToCanvas(context)
log.time('canvas to data url')
let dataUrl = canvas.toDataURL(type, quality)
if (
['image/png', 'image/jpeg'].includes(type)
&& dpi
&& SUPPORT_ATOB
&& SUPPORT_BTOA
) {
const [format, body] = dataUrl.split(',')
let headerLength = 0
let overwritepHYs = false
if (type === 'image/png') {
const b64Index = detectPhysChunkFromDataUrl(body)
// 28 bytes in dataUrl are 21bytes, length of phys chunk with everything inside.
if (b64Index >= 0) {
headerLength = Math.ceil((b64Index + 28) / 3) * 4
overwritepHYs = true
}
else {
headerLength = 33 / 3 * 4
}
}
else if (type === 'image/jpeg') {
headerLength = 18 / 3 * 4
}
// 33 bytes are ok for pngs and jpegs
// to contain the information.
const stringHeader = body.substring(0, headerLength)
const restOfData = body.substring(headerLength)
const headerBytes = window.atob(stringHeader)
const uint8Array = new Uint8Array(headerBytes.length)
for (let i = 0; i < uint8Array.length; i++) {
uint8Array[i] = headerBytes.charCodeAt(i)
}
const finalArray = type === 'image/png'
? changePngDpi(uint8Array, dpi, overwritepHYs)
: changeJpegDpi(uint8Array, dpi)
const base64Header = window.btoa(String.fromCharCode(...finalArray))
dataUrl = [format, ',', base64Header, restOfData].join('')
}
log.timeEnd('canvas to data url')
return dataUrl
}