code: fonts optimization

This commit is contained in:
ShawnPhang 2023-10-15 12:58:18 +08:00
parent 6d00a04bfd
commit c3d34bc35e
15 changed files with 106 additions and 75 deletions

View File

@ -109,18 +109,14 @@ A考虑到服务端的开发语言、数据库类型都可能不尽相同
或许你在工作中有类似的需求,或许你也对开发编辑器感兴趣,希望这个项目能给到你一些微薄帮助! 或许你在工作中有类似的需求,或许你也对开发编辑器感兴趣,希望这个项目能给到你一些微薄帮助!
目前本项目也还在迭代中,有很多的不足,我也是一边学习一边成长。开源不易,希望看到这里的你可以给本项目点个 **Star** 支持一下~ 目前本项目也还在迭代中,有很多的不足,我也是一边学习一边成长。
[ -> 实时迭代计划文档](https://xp.palxp.cn/#/articles/1689319986889?id=%e8%bf%ad%e4%bb%a3%e8%ae%a1%e5%88%92)
开源不易,别忘了给本项目点个 **Star** 支持一下~
[![Star History Chart](https://api.star-history.com/svg?repos=palxiao/poster-design&type=Date)](https://star-history.com/#palxiao/poster-design&Date) [![Star History Chart](https://api.star-history.com/svg?repos=palxiao/poster-design&type=Date)](https://star-history.com/#palxiao/poster-design&Date)
#### 部分迭代计划:
- [ ] P1: 文字特效属性编辑面板开发
- [ ] P1字体抽取功能
- [ ] P1PSD 解析重构(涉及基础库更换)
[ -> 完整后续迭代计划文档](https://xp.palxp.cn/#/articles/1689319986889?id=%e8%bf%ad%e4%bb%a3%e8%ae%a1%e5%88%92)
### LICENSE ### LICENSE
[MIT License](https://github.com/palxiao/poster-design/blob/main/LICENSE) [MIT License](https://github.com/palxiao/poster-design/blob/main/LICENSE)

View File

@ -3,7 +3,7 @@
* @Date: 2021-08-27 14:42:15 * @Date: 2021-08-27 14:42:15
* @Description: AI相关接口 * @Description: AI相关接口
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-30 12:08:01 * @LastEditTime: 2023-10-13 00:07:19
*/ */
import fetch from '@/utils/axios' import fetch from '@/utils/axios'

View File

@ -3,7 +3,7 @@
* @Date: 2021-08-27 14:42:15 * @Date: 2021-08-27 14:42:15
* @Description: * @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-28 11:24:13 * @LastEditTime: 2023-10-13 00:25:25
*/ */
import fetch from '@/utils/axios' import fetch from '@/utils/axios'
@ -15,7 +15,7 @@ export const getList = (params: Type.Object = {}) => fetch('design/material', pa
// 获取字体 // 获取字体
export const getFonts = (params: Type.Object = {}) => fetch('design/fonts', params) export const getFonts = (params: Type.Object = {}) => fetch('design/fonts', params)
export const getFontSub = (params: Type.Object = {}) => fetch('design/font_sub', params) export const getFontSub = (params: Type.Object = {}, extra: any = {}) => fetch('design/font_sub', params, 'get', {}, extra)
// 图库列表 // 图库列表
export const getImagesList = (params: Type.Object = {}) => fetch('design/imgs', params, 'get') export const getImagesList = (params: Type.Object = {}) => fetch('design/imgs', params, 'get')

View File

@ -15,6 +15,7 @@ body {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
color: #333333; color: #333333;
font-family: Hiragino Sans GB, Hiragino Sans GB W3, Arial, Microsoft Yahei, STHeiti, sans-serif; font-family: Hiragino Sans GB, Hiragino Sans GB W3, Arial, Microsoft Yahei, STHeiti, sans-serif;
overflow: hidden;
} }
* { * {

View File

@ -2,12 +2,13 @@
* @Author: ShawnPhang * @Author: ShawnPhang
* @Date: 2022-01-08 09:43:37 * @Date: 2022-01-08 09:43:37
* @Description: * @Description:
* @LastEditors: ShawnPhang <site: book.palxp.com> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-07-25 11:13:01 * @LastEditTime: 2023-10-13 01:30:33
*/ */
// import { isSupportFontFamily, blob2Base64 } from './utils' // import { isSupportFontFamily, blob2Base64 } from './utils'
import { getFonts } from '@/api/material' import { getFonts } from '@/api/material'
// import store from '@/store'
const nowVersion = '2' // 当前字体文件版本更新,将刷新前端缓存
const fontList: any = [] const fontList: any = []
// const download: any = {} // const download: any = {}
@ -16,7 +17,7 @@ export const useFontStore = {
// download, // download,
async init() { async init() {
this.list = [] this.list = []
localStorage.getItem('FONTS_VERSION') !== '1' && localStorage.removeItem('FONTS') localStorage.getItem('FONTS_VERSION') !== nowVersion && localStorage.removeItem('FONTS')
const localFonts: any = localStorage.getItem('FONTS') ? JSON.parse(localStorage.getItem('FONTS') || '') : [] const localFonts: any = localStorage.getItem('FONTS') ? JSON.parse(localStorage.getItem('FONTS') || '') : []
if (localFonts.length > 0) { if (localFonts.length > 0) {
this.list.push(...localFonts) this.list.push(...localFonts)
@ -26,12 +27,12 @@ export const useFontStore = {
const res = await getFonts({ pageSize: 400 }) const res = await getFonts({ pageSize: 400 })
this.list.unshift( this.list.unshift(
...res.list.map((x: any) => { ...res.list.map((x: any) => {
const { alias, oid, value, preview, woff, lang } = x const { id, alias, oid, value, preview, woff, lang } = x
return { id: oid, value, preview, alias, url: woff, lang } return { id, oid, value, preview, alias, url: woff, lang }
}), }),
) )
localStorage.setItem('FONTS', JSON.stringify(this.list)) localStorage.setItem('FONTS', JSON.stringify(this.list))
localStorage.setItem('FONTS_VERSION', '1') localStorage.setItem('FONTS_VERSION', nowVersion)
} }
// store.dispatch('setFonts', this.list) // store.dispatch('setFonts', this.list)
}, },

View File

@ -77,7 +77,7 @@ export function filterSkyFonts() {
// ); // );
const textClouds: any = [] const textClouds: any = []
;((textClouds as unknown) as CloudText[]).forEach((cloud) => { ;(textClouds as unknown as CloudText[]).forEach((cloud) => {
// 找到文字组件字体 // 找到文字组件字体
if (cloud.fontFamily && !fonts.includes(cloud.fontFamily)) { if (cloud.fontFamily && !fonts.includes(cloud.fontFamily)) {
fonts.push(cloud.fontFamily) fonts.push(cloud.fontFamily)
@ -114,6 +114,10 @@ export function base642Blob(b64Data: string, contentType = '', sliceSize = 512)
export async function blob2Base64(blob: Blob): Promise<string> { export async function blob2Base64(blob: Blob): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (blob.type === 'application/json') {
resolve('')
return
}
const fileReader = new FileReader() const fileReader = new FileReader()
fileReader.onload = () => { fileReader.onload = () => {
resolve(fileReader.result as string) resolve(fileReader.result as string)

View File

@ -3,7 +3,7 @@
* @Date: 2022-02-11 18:48:23 * @Date: 2022-02-11 18:48:23
* @Description: 组件列表 * @Description: 组件列表
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-10-08 22:57:34 * @LastEditTime: 2023-10-13 18:48:25
--> -->
<template> <template>
<div class="wrap"> <div class="wrap">
@ -15,7 +15,7 @@
<div class="header">其它</div> <div class="header">其它</div>
<div class="item" @click="openImageCutout"> <div class="item" @click="openImageCutout">
<i class="icon sd-AI_zhineng" /> <i class="icon sd-AI_zhineng" />
<div class="text"><span>在线抠图</span> <span class="desc">上传图像一键去除背景</span></div> <div class="text"><span>智能抠图</span> <span class="desc">上传图像一键去除背景</span></div>
</div> </div>
<imageCutout ref="imageCutout" /> <imageCutout ref="imageCutout" />
</div> </div>

View File

@ -1,28 +1,15 @@
<!-- <!--
* @Author: ShawnPhang * @Author: ShawnPhang
* @Date: 2021-08-02 19:10:06 * @Date: 2021-08-02 19:10:06
* @Description: * @Description: 选项选择未拆分字体选择器
* @LastEditors: ShawnPhang * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2022-04-07 14:29:42 * @LastEditTime: 2023-10-14 21:03:17
--> -->
<template> <template>
<div id="value-select" ref="select" :style="{ width: inputWidth }"> <div id="value-select" ref="select" :style="{ width: inputWidth }">
<p v-if="label" class="input-label"> <p v-if="label" class="input-label">
{{ label }} {{ label }}
</p> </p>
<!-- <div class="input-wrap" :class="{ active: inputBorder }" :style="{ width: inputWidth }">
<input class="real-input" :style="{ textAlign: textAlign }" :class="{ disable: !disable }" :readonly="readonly ? 'readonly' : ''" type="text" :value="showValue" @input="innerValue = $event.target.value.replace(RegExp(suffix), '')" @focus="inputBorder = true" @blur="inputBorder = false" />
<div class="op-btn">
<div class="down" @click="inputBorder = !inputBorder"></div>
</div>
</div>
<el-popover ref="list" v-model="inputBorder" placement="bottom-start" trigger="click" :width="width" popper-class="value-select-list">
<ul v-if="data" class="list-ul">
<li v-for="listItem in data" :key="typeof listItem === 'object' ? listItem.name : listItem" :class="{ active: listItem == innerValue }" @click="selectItem(listItem)">
{{ (typeof listItem === 'object' ? listItem.name : listItem) + suffix }}
</li>
</ul>
</el-popover> -->
<el-popover placement="bottom-end" width="auto"> <el-popover placement="bottom-end" width="auto">
<!-- 单列表 --> <!-- 单列表 -->
<ul v-if="data && Array.isArray(data)" class="list-ul"> <ul v-if="data && Array.isArray(data)" class="list-ul">
@ -32,16 +19,18 @@
</li> </li>
</ul> </ul>
<!-- tab分类列表 --> <!-- tab分类列表 -->
<el-tabs v-else v-model="activeTab"> <div v-else class="tabs-wrap">
<el-tabs v-model="activeTab">
<el-tab-pane v-for="(val, key, i) in data" :key="'tab' + i" :label="key" :name="key"> <el-tab-pane v-for="(val, key, i) in data" :key="'tab' + i" :label="key" :name="key">
<ul class="list-ul"> <ul class="list-ul">
<li v-for="listItem in data[key]" :key="typeof listItem === 'object' ? listItem.alias : listItem" :class="{ active: listItem == innerValue }" @click="selectItem(listItem)"> <li v-for="listItem in data[key]" :key="typeof listItem === 'object' ? listItem.alias : listItem" :class="{ active: listItem == innerValue }" @click="selectItem(listItem)">
<img v-if="listItem.preview" class="preview" :src="listItem.preview" /> <img v-if="listItem.preview" class="preview" :src="listItem.preview" />
<span v-else>{{ (typeof listItem === 'object' ? listItem.alias : listItem) + suffix }}</span> <span v-else :style="{ fontFamily: `'${listItem.value}'` }">{{ (typeof listItem === 'object' ? listItem.alias : listItem) + suffix }}</span>
</li> </li>
</ul> </ul>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</div>
<template #reference> <template #reference>
<div :class="['input-wrap', { active: inputBorder }]" :style="{ width: inputWidth }"> <div :class="['input-wrap', { active: inputBorder }]" :style="{ width: inputWidth }">
<!-- <img v-if="innerPreview" class="preview" :src="innerPreview" /> --> <!-- <img v-if="innerPreview" class="preview" :src="innerPreview" /> -->
@ -298,4 +287,8 @@ export default {
height: 1.6em; height: 1.6em;
} }
} }
.tabs-wrap {
width: 210px;
}
</style> </style>

View File

@ -0,0 +1,22 @@
/*
* @Author: ShawnPhang
* @Date: 2023-10-14 20:16:48
* @Description: 使
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-10-14 20:29:26
*/
import store from '@/store'
import { toRaw } from 'vue'
export default () => {
const collector = new Set()
const fonts: any = {}
const { dWidgets: widgets } = store.getters
for (let i = 0; i < widgets.length; i++) {
const { type, fontClass } = widgets[i]
if (type === 'w-text') {
collector.add(fontClass.id)
fonts[fontClass.id] = toRaw(fontClass)
}
}
return Array.from(collector).map((id: any) => fonts[id])
}

View File

@ -70,10 +70,10 @@ export default {
fontSize: 24, fontSize: 24,
zoom: 1, zoom: 1,
fontClass: { fontClass: {
alias: '素材集市酷方体', alias: '站酷快乐体',
id: 33925853, id: 543,
value: 'sucaijishikufangti', value: 'zcool-kuaile-regular',
url: 'https://res.palxp.cn/static/fonts/20200809-152508-8654.woff', url: 'https://lib.baomitu.com/fonts/zcool-kuaile/zcool-kuaile-regular.woff2',
}, },
fontFamily: 'SourceHanSansSC-Regular', fontFamily: 'SourceHanSansSC-Regular',
fontWeight: 'normal', fontWeight: 'normal',

View File

@ -51,8 +51,8 @@
<script> <script>
// //
const NAME = 'w-text-style' const NAME = 'w-text-style'
import api from '@/api' // import api from '@/api'
import _config from '@/config' // import _config from '@/config'
import { mapGetters, mapActions } from 'vuex' import { mapGetters, mapActions } from 'vuex'
import { styleIconList1, styleIconList2, alignIconList } from '../../../../assets/data/TextIconsData' import { styleIconList1, styleIconList2, alignIconList } from '../../../../assets/data/TextIconsData'
import layerIconList from '@/assets/data/LayerIconList' import layerIconList from '@/assets/data/LayerIconList'
@ -64,6 +64,7 @@ import textInputArea from '../../settings/textInputArea.vue'
import valueSelect from '../../settings/valueSelect.vue' import valueSelect from '../../settings/valueSelect.vue'
import effectWrap from '../../settings/EffectSelect/TextWrap.vue' import effectWrap from '../../settings/EffectSelect/TextWrap.vue'
import { useFontStore } from '@/common/methods/fonts' import { useFontStore } from '@/common/methods/fonts'
import usePageFontsFilter from './pageFontsFilter.ts'
export default { export default {
name: NAME, name: NAME,
@ -124,11 +125,13 @@ export default {
// if (!this.isDraw) { // if (!this.isDraw) {
// useFontStore().init() // useFontStore().init()
const localFonts = useFontStore.list const localFonts = useFontStore.list
const fontLists = { 中文: [], 英文: [] } const fontLists = { 当前页面: [], 中文: [], 英文: [] }
for (const font of localFonts) { for (const font of localFonts) {
const { id, value, url, alias, preview, lang } = font const { id, oid, value, url, alias, preview, lang } = font
lang === 'zh' ? fontLists['中文'].unshift({ id, value, url, alias, preview }) : fontLists['英文'].unshift({ id, value, url, alias, preview }) const item = { id, oid, value, url, alias, preview }
lang === 'zh' ? fontLists['中文'].unshift(item) : fontLists['英文'].unshift(item)
} }
fontLists['当前页面'] = usePageFontsFilter()
this.fontClassList = fontLists this.fontClassList = fontLists
// } // }
// const isDev = process.env.NODE_ENV === 'development' // const isDev = process.env.NODE_ENV === 'development'
@ -180,6 +183,9 @@ export default {
value: value, value: value,
pushHistory: false, pushHistory: false,
}) })
setTimeout(() => {
key === 'fontClass' && (this.fontClassList['当前页面'] = usePageFontsFilter())
}, 300)
}, },
layerAction(item) { layerAction(item) {
this.updateLayerIndex({ this.updateLayerIndex({

View File

@ -18,4 +18,5 @@ export default {
ICONFONT_URL: '//at.alicdn.com/t/font_2717063_ypy8vprc3b.css?display=swap', ICONFONT_URL: '//at.alicdn.com/t/font_2717063_ypy8vprc3b.css?display=swap',
ICONFONT_EXTRA: '//at.alicdn.com/t/c/font_3228074_zubqmza1sdk.css', ICONFONT_EXTRA: '//at.alicdn.com/t/c/font_3228074_zubqmza1sdk.css',
QINIUYUN_PLUGIN: 'https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/qiniu-js/2.5.5/qiniu.min.js', QINIUYUN_PLUGIN: 'https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/qiniu-js/2.5.5/qiniu.min.js',
supportSubFont: true, // 是否开启服务端字体压缩
} }

View File

@ -1,29 +1,34 @@
/* /*
* @Author: ShawnPhang * @Author: ShawnPhang
* @Date: 2023-08-23 17:37:16 * @Date: 2023-08-23 17:37:16
* @Description: * @Description:
* @LastEditors: ShawnPhang <site: book.palxp.com> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-08-23 17:48:34 * @LastEditTime: 2023-10-14 18:31:29
*/ */
/**
* ttf/otf这种原始字体支持提取false
*/
import _config from '@/config'
export const fontWithDraw = _config.supportSubFont // true 开启false 关闭
import api from '@/api' import api from '@/api'
import { blob2Base64, generateFontStyle } from '@/common/methods/fonts/utils' import { blob2Base64, generateFontStyle } from '@/common/methods/fonts/utils'
export const fontWithDraw = true // true开启false关闭
export const font2style = async (fontContent: any, fontData: any = []) => { export const font2style = async (fontContent: any, fontData: any = []) => {
return new Promise((resolve: Function) => { return new Promise((resolve: Function) => {
Promise.all( Promise.all(
// 提取字体子集。只有ttf/otf这种原始字体支持提取如果服务端不支持则关闭该功能以保证页面能加载字体。
Object.keys(fontContent).map(async (key) => { Object.keys(fontContent).map(async (key) => {
const font = fontData.find((font: any) => font.value === key) as any const font = fontData.find((font: any) => font.value === key) as any
if (font.id) { if (font.id) {
const extra = font.oid ? {} : { responseType: 'blob' }
const params = {
font_id: font.oid,
id: font.id,
content: shortText(fontContent[key]),
}
try { try {
const base64 = await api.material.getFontSub({ const result = await api.material.getFontSub(params, extra)
font_id: font.id, fontContent[key] = font.oid ? result : await blob2Base64(result)
url: font.url,
content: 'Aa' + fontContent[key],
})
fontContent[key] = base64
} catch (e) { } catch (e) {
console.log('字体获取失败', e) console.log('字体获取失败', e)
} }
@ -37,3 +42,9 @@ export const font2style = async (fontContent: any, fontData: any = []) => {
}) })
}) })
} }
function shortText(text: string) {
// 文字去重
const textArr = Array.from(new Set(text.split('')))
return textArr.join('')
}

View File

@ -90,10 +90,6 @@ export default defineComponent({
await preloadBg.imgs() await preloadBg.imgs()
} }
try { try {
const { list } = await api.material.getFonts({ ids: fontData.map((x: any) => x.id) })
fontData.forEach((item: any) => {
item.url = list.find((x: any) => x.oid == item.id)?.ttf
})
fontWithDraw && (await font2style(fontContent, fontData)) fontWithDraw && (await font2style(fontContent, fontData))
// console.log('1. base64 yes') // console.log('1. base64 yes')
const preload = new Preload(imgsData) const preload = new Preload(imgsData)

View File

@ -3,7 +3,7 @@
* @Date: 2022-01-10 14:57:53 * @Date: 2022-01-10 14:57:53
* @Description: Psd文件解析 * @Description: Psd文件解析
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-15 12:57:02 * @LastEditTime: 2023-10-13 00:12:11
--> -->
<template> <template>
<div id="page-design-index" ref="pageDesignIndex"> <div id="page-design-index" ref="pageDesignIndex">
@ -56,7 +56,7 @@ import designBoard from '@/components/modules/layout/designBoard.vue'
import zoomControl from '@/components/modules/layout/zoomControl.vue' import zoomControl from '@/components/modules/layout/zoomControl.vue'
import HeaderOptions from './components/UploadTemplate.vue' import HeaderOptions from './components/UploadTemplate.vue'
import ProgressLoading from '@/components/common/ProgressLoading/index.vue' import ProgressLoading from '@/components/common/ProgressLoading/index.vue'
import MyWorker from '@/utils/plugins/webWorker' // import MyWorker from '@/utils/plugins/webWorker'
import { processPSD2Page } from '@/utils/plugins/psd' import { processPSD2Page } from '@/utils/plugins/psd'
export default defineComponent({ export default defineComponent({