mirror of
https://github.com/palxiao/poster-design.git
synced 2025-06-08 03:19:59 +08:00
feat: update psd.js & run on WebWorker
This commit is contained in:
parent
ebf8fa9bba
commit
2878064b76
23
package-lock.json
generated
23
package-lock.json
generated
@ -14,7 +14,6 @@
|
||||
"@palxp/color-picker": "workspace:*",
|
||||
"@palxp/image-extraction": "workspace:*",
|
||||
"@scena/guides": "^0.18.1",
|
||||
"@webtoon/psd": "^0.4.0",
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"cropperjs": "^1.6.1",
|
||||
@ -30,6 +29,7 @@
|
||||
"nanoid": "^3.1.23",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pinia": "^2.1.7",
|
||||
"psd.js": "^3.9.0",
|
||||
"qr-code-styling": "^1.6.0-rc.1",
|
||||
"selecto": "^1.13.0",
|
||||
"throttle-debounce": "^3.0.1",
|
||||
@ -1515,11 +1515,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@webtoon/psd": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@webtoon/psd/-/psd-0.4.0.tgz",
|
||||
"integrity": "sha512-ztriE8oFOamRrV9opBURDy+JMiyhur2//vOXsC5CgdnYCB0L1Lnaag4NzP8N+NFCj7uNz9JRYtPmAbQMSDLIsQ=="
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
||||
@ -3397,6 +3392,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pngjs": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-3.4.0.tgz",
|
||||
"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.35",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
|
||||
@ -3445,6 +3448,14 @@
|
||||
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/psd.js": {
|
||||
"version": "3.9.0",
|
||||
"resolved": "https://registry.npmmirror.com/psd.js/-/psd.js-3.9.0.tgz",
|
||||
"integrity": "sha512-gTNUszC/hjS+F3O0JkdWOdN7dVZzOaYfyF7X1VD0UOue5iWOaFzfxFbfZgYnXtYS1pze9V10Hd/K0pWY3My54g==",
|
||||
"dependencies": {
|
||||
"pngjs": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
|
@ -17,7 +17,6 @@
|
||||
"@palxp/color-picker": "workspace:*",
|
||||
"@palxp/image-extraction": "workspace:*",
|
||||
"@scena/guides": "^0.18.1",
|
||||
"@webtoon/psd": "^0.4.0",
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"cropperjs": "^1.6.1",
|
||||
@ -33,6 +32,7 @@
|
||||
"nanoid": "^3.1.23",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pinia": "^2.1.7",
|
||||
"psd.js": "^3.9.0",
|
||||
"qr-code-styling": "^1.6.0-rc.1",
|
||||
"selecto": "^1.13.0",
|
||||
"throttle-debounce": "^3.0.1",
|
||||
|
32082
public/psd.js
32082
public/psd.js
File diff suppressed because it is too large
Load Diff
5
src/types/vue-ts.d.ts
vendored
5
src/types/vue-ts.d.ts
vendored
@ -2,8 +2,8 @@
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2023-07-11 14:21:33
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||
* @LastEditTime: 2023-07-11 17:01:37
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-17 15:56:39
|
||||
*/
|
||||
import Vue, { VNode } from 'vue'
|
||||
|
||||
@ -41,6 +41,7 @@ declare module 'dayjs'
|
||||
declare module 'fontfaceobserver'
|
||||
declare module 'throttle-debounce'
|
||||
declare module 'html2canvas'
|
||||
declare module 'psd.js'
|
||||
|
||||
declare module 'vue/types/vue' {
|
||||
interface Vue {
|
||||
|
21
src/utils/plugins/psd/helper.ts
Normal file
21
src/utils/plugins/psd/helper.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2024-08-17 18:45:24
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-17 18:46:58
|
||||
*/
|
||||
export function createBase64(src: any, { width, height }: any) {
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
const context: any = canvas.getContext('2d', { willReadFrequently: true })
|
||||
const imageData = context.getImageData(0, 0, width, height)
|
||||
const pixelData = imageData.data
|
||||
const len = src.length
|
||||
for (let i = 0; i < len; i++) {
|
||||
pixelData[i] = src[i]
|
||||
}
|
||||
context.putImageData(imageData, 0, 0)
|
||||
return canvas.toDataURL('image/png')
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
// import { colorer } from './color'
|
||||
import PSD from 'psd.js'
|
||||
import { RGBA2HexA } from './color/color'
|
||||
const colorer = { RGBA2HexA }
|
||||
|
||||
import * as helper from './helper'
|
||||
export const createBase64 = helper.createBase64
|
||||
|
||||
export const CLOUD_TYPE = {
|
||||
text: 'text',
|
||||
image: 'image',
|
||||
@ -12,7 +15,7 @@ export const WRITING_MODE = {
|
||||
}
|
||||
|
||||
export async function parsePSDFromURL(url: string) {
|
||||
return await (window as any).PSD.fromURL(url)
|
||||
return await PSD.fromURL(url)
|
||||
}
|
||||
|
||||
function toRGBAColor(data: number[]) {
|
||||
@ -129,9 +132,9 @@ function toCloudTextConfig(data: any, layer: any) {
|
||||
function toCloudImageConfig(data: any, layer: any) {
|
||||
// const { type, b64 } = splitBase64(layer.image.toBase64());
|
||||
// const src = URL.createObjectURL(b64toBlob(b64, type));
|
||||
|
||||
return {
|
||||
src: layer?.image?.toBase64(),
|
||||
src: layer?.image?.pixelData,
|
||||
// src: layer?.image?.toBase64(),
|
||||
// src: layer.image.toPng(),
|
||||
type: CLOUD_TYPE.image,
|
||||
width: data.width,
|
||||
@ -152,7 +155,7 @@ function toCloud(data: any, layer: any) {
|
||||
|
||||
export async function convertPSD2Page(psd: any) {
|
||||
const { children, document: doc } = psd.tree().export()
|
||||
console.log(psd.tree().export())
|
||||
console.log('PSD_tree_export', psd.tree().export())
|
||||
|
||||
// const node = psd.tree().childrenAtPath('taylor-vick-M5tzZtFCOfs-unsplash')[0]
|
||||
// console.log(node)
|
||||
@ -221,31 +224,9 @@ export async function convertPSD2Page(psd: any) {
|
||||
return page
|
||||
}
|
||||
|
||||
function file2Base64(file: any) {
|
||||
return new Promise((resolve) => {
|
||||
// const blob = new Blob(file)
|
||||
// resolve(URL.createObjectURL(blob))
|
||||
// const reader = new FileReader()
|
||||
// reader.onload = function(e: any) {
|
||||
// resolve(e.target.result)
|
||||
// }
|
||||
// reader.readAsDataURL(blob)
|
||||
let binary = ''
|
||||
const bytes = new Uint8Array(file)
|
||||
const len = bytes.byteLength
|
||||
for (let i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i])
|
||||
}
|
||||
resolve('data:image/png;base64,' + window.btoa(binary))
|
||||
// resolve('data:image/png;base64,' + btoa(new Uint8Array(file).reduce((data, byte) => data + String.fromCharCode(byte), '')))
|
||||
})
|
||||
}
|
||||
|
||||
export async function processPSD2Page(file: File) {
|
||||
const url = URL.createObjectURL(file)
|
||||
const psd = await parsePSDFromURL(url)
|
||||
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
return convertPSD2Page(psd)
|
||||
}
|
||||
|
@ -3,19 +3,26 @@
|
||||
* @Date: 2023-09-14 11:33:44
|
||||
* @Description: 加载PSD解析
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-09-14 18:15:44
|
||||
* @LastEditTime: 2024-08-17 18:57:15
|
||||
*/
|
||||
import Psd from '@webtoon/psd'
|
||||
// import Psd from '@webtoon/psd'
|
||||
|
||||
// onmessage = async (e) => {
|
||||
// const result = await e.data.arrayBuffer()
|
||||
// const rawPsdFile = Psd.parse(result)
|
||||
// console.log(111, rawPsdFile)
|
||||
|
||||
// const { width, height } = rawPsdFile
|
||||
// const psdFile = { width, height }
|
||||
|
||||
// const compositeBuffer = await rawPsdFile.composite()
|
||||
|
||||
// self.postMessage({ psdFile, compositeBuffer })
|
||||
// }
|
||||
|
||||
import { processPSD2Page } from '@/utils/plugins/psd'
|
||||
|
||||
onmessage = async (e) => {
|
||||
const result = await e.data.arrayBuffer()
|
||||
const rawPsdFile = Psd.parse(result)
|
||||
console.log(111, rawPsdFile)
|
||||
|
||||
const { width, height } = rawPsdFile
|
||||
const psdFile = { width, height }
|
||||
|
||||
const compositeBuffer = await rawPsdFile.composite()
|
||||
|
||||
self.postMessage({ psdFile, compositeBuffer })
|
||||
const data = await processPSD2Page(e.data)
|
||||
self.postMessage({ data })
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2022-01-10 14:57:53
|
||||
* @Description: Psd文件解析
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-15 18:00:32
|
||||
* @LastEditTime: 2024-08-17 18:53:35
|
||||
-->
|
||||
<template>
|
||||
<div id="page-design-index" ref="pageDesignIndex">
|
||||
@ -27,13 +27,7 @@
|
||||
<design-board class="page-design-wrap" pageDesignCanvasId="page-design-canvas">
|
||||
<div v-if="state.isDone" class="shelter" :style="{ width: (dPage.width * dZoom) / 100 + 'px', height: (dPage.height * dZoom) / 100 + 'px' }"></div>
|
||||
<uploader v-else accept=".psd" :hold="true" :drag="true" class="uploader" @load="selectFile">
|
||||
<div class="uploader__box">
|
||||
<img
|
||||
style="margin-right: 1rem"
|
||||
src="https://cdn.dancf.com/design/svg/icon_psdimport.37e6f23e.svg"
|
||||
alt="upload"
|
||||
/> 在此拖入或选择 PSD 文件
|
||||
</div>
|
||||
<div class="uploader__box"><img style="margin-right: 1rem" src="https://cdn.dancf.com/design/svg/icon_psdimport.37e6f23e.svg" alt="upload" /> 在此拖入或选择 PSD 文件</div>
|
||||
</uploader>
|
||||
</design-board>
|
||||
<style-panel v-show="state.isDone"></style-panel>
|
||||
@ -45,11 +39,7 @@
|
||||
<!-- 旋转缩放组件 -->
|
||||
<Moveable />
|
||||
<!-- 遮罩百分比进度条 -->
|
||||
<ProgressLoading
|
||||
:percent="state.downloadPercent" :text="state.downloadText"
|
||||
:cancelText="state.cancelText" :msg="state.downloadMsg"
|
||||
@cancel="cancel" @done="state.downloadPercent = 0"
|
||||
/>
|
||||
<ProgressLoading :percent="state.downloadPercent" :text="state.downloadText" :cancelText="state.cancelText" :msg="state.downloadMsg" @cancel="cancel" @done="state.downloadPercent = 0" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -68,8 +58,9 @@ import designBoard from '@/components/modules/layout/designBoard/index.vue'
|
||||
import zoomControl from '@/components/modules/layout/zoomControl/index.vue'
|
||||
import HeaderOptions, { TEmitChangeData } from './components/UploadTemplate.vue'
|
||||
import ProgressLoading from '@/components/common/ProgressLoading/index.vue'
|
||||
// import MyWorker from '@/utils/plugins/webWorker'
|
||||
import { processPSD2Page } from '@/utils/plugins/psd'
|
||||
import MyWorker from '@/utils/plugins/webWorker'
|
||||
// import { processPSD2Page } from '@/utils/plugins/psd'
|
||||
import { createBase64 } from '@/utils/plugins/psd'
|
||||
// import { useSetupMapGetters } from '@/common/hooks/mapGetters'
|
||||
import { wTextSetting } from '@/components/modules/widgets/wText/wTextSetting'
|
||||
import { useCanvasStore, useControlStore, useWidgetStore, useGroupStore } from '@/store'
|
||||
@ -106,23 +97,17 @@ const { dZoom } = storeToRefs(useCanvasStore())
|
||||
const zoomControlRef = ref<typeof zoomControl | null>()
|
||||
|
||||
let loading: ReturnType<typeof useLoading> | null = null
|
||||
// const myWorker = new MyWorker('loadPSD')
|
||||
const myWorker = new MyWorker('loadPSD')
|
||||
|
||||
onMounted(async () => {
|
||||
groupStore.initGroupJson(JSON.stringify(wGroupSetting))
|
||||
await nextTick()
|
||||
if (zoomControlRef.value){
|
||||
if (zoomControlRef.value) {
|
||||
zoomControlRef.value.screenChange()
|
||||
}
|
||||
state.isDone = false
|
||||
})
|
||||
|
||||
function loadJS() {
|
||||
const link_element = document.createElement('script')
|
||||
link_element.setAttribute('src', '/psd.js')
|
||||
document.head.appendChild(link_element)
|
||||
}
|
||||
|
||||
async function selectFile(file: File) {
|
||||
loading = useLoading()
|
||||
await loadPSD(file)
|
||||
@ -130,31 +115,27 @@ async function selectFile(file: File) {
|
||||
state.isDone = true
|
||||
}
|
||||
|
||||
async function loadPSD(file: File) {
|
||||
// const { compositeBuffer, psdFile } = await myWorker.start(file)
|
||||
const data = await processPSD2Page(file)
|
||||
|
||||
setTimeout(async () => {
|
||||
const types: any = {
|
||||
const types: any = {
|
||||
text: wTextSetting,
|
||||
image: wImageSetting,
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPSD(file: File) {
|
||||
// const { compositeBuffer, psdFile } = await myWorker.start(file)
|
||||
const { data }: any = await myWorker.start(file)
|
||||
// const data = await processPSD2Page(file)
|
||||
|
||||
for (let i = 0; i < data.clouds.length; i++) {
|
||||
const x: any = data.clouds[i]
|
||||
const rawData = JSON.parse(JSON.stringify(types[x.type])) || {}
|
||||
delete x.type
|
||||
x.src && (x.imgUrl = x.src) && delete x.src
|
||||
x.src && (x.imgUrl = createBase64(x.src, { width: x.width, height: x.height })) && delete x.src
|
||||
widgetStore.addWidget(Object.assign(rawData, x))
|
||||
// store.dispatch('addWidget', Object.assign(rawData, x))
|
||||
}
|
||||
|
||||
const { width, height, background: bg } = data
|
||||
|
||||
pageStore.setDPage(Object.assign(pageStore.dPage, { width, height, backgroundColor: bg.color, backgroundImage: bg.image }))
|
||||
// store.commit('setDPage', Object.assign(store.getters.dPage, { width, height, backgroundColor: bg.color, backgroundImage: bg.image }))
|
||||
|
||||
pageStore.setDPage(Object.assign(pageStore.dPage, { width, height, backgroundColor: bg.color, backgroundImage: createBase64(bg.image, { width, height }) }))
|
||||
await loadDone()
|
||||
}, 10)
|
||||
}
|
||||
|
||||
async function clear() {
|
||||
@ -178,7 +159,7 @@ const cancel = () => {
|
||||
window.open(`${window.location.protocol + '//' + window.location.host}/home?id=${route.query.id}`)
|
||||
}
|
||||
|
||||
const {handleKeydowm, handleKeyup, dealCtrl} = shortcuts.methods
|
||||
const { handleKeydowm, handleKeyup, dealCtrl } = shortcuts.methods
|
||||
|
||||
// ...mapGetters(['dPage', 'dZoom']),
|
||||
|
||||
@ -188,7 +169,6 @@ onMounted(() => {
|
||||
const instance = getCurrentInstance()
|
||||
document.addEventListener('keydown', handleKeydowm(controlStore, checkCtrl, instance, dealCtrl), false)
|
||||
document.addEventListener('keyup', handleKeyup(controlStore, checkCtrl), false)
|
||||
loadJS()
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
@ -218,7 +198,6 @@ function jump2word() {
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
loadJS,
|
||||
selectFile,
|
||||
clear,
|
||||
cancel,
|
||||
|
Loading…
x
Reference in New Issue
Block a user