Commit 9355f0ca authored by rockyl's avatar rockyl

转换jpg功能

parent a067b144
...@@ -250,6 +250,7 @@ ...@@ -250,6 +250,7 @@
"Previous Conflict": "上一个冲突", "Previous Conflict": "上一个冲突",
"Next Conflict": "下一个冲突", "Next Conflict": "下一个冲突",
"To Verify": "去验证", "To Verify": "去验证",
"Transform options": "转换参数",
"eventGroup": { "eventGroup": {
"in": "接收", "in": "接收",
"out": "派发" "out": "派发"
...@@ -394,7 +395,8 @@ ...@@ -394,7 +395,8 @@
"assetItemMenu": { "assetItemMenu": {
"rename": "重命名", "rename": "重命名",
"replace": "替换", "replace": "替换",
"combine": "合并" "combine": "合并",
"to-jpg": "转换为JPG"
}, },
"customCmds": { "customCmds": {
"z-for": "循环", "z-for": "循环",
......
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
*/ */
import Vue from "vue"; import Vue from "vue";
import {envApi} from "../../api"; import {editorApi, envApi} from "../../api";
import {Parser} from "svgaplayerweb"; import {Parser} from "svgaplayerweb";
import db from "../../utils/db-storage";
import events from "@/global-events"
const storeKey = 'code-sync-serve-config'; const storeKey = 'code-sync-serve-config';
const svgaParser = new Parser(); const svgaParser = new Parser();
...@@ -125,3 +127,24 @@ export const editorStore = { ...@@ -125,3 +127,24 @@ export const editorStore = {
}, },
} }
}; };
export async function uploadFiles(files) {
const failedList = [];
let ps = [];
for (let file of files) {
events.$emit('upload-indicator', true);
ps.push(
editorApi.uploadFile(file).catch(e => {
failedList.push(file);
}).finally(() => {
events.$emit('upload-indicator', false);
})
);
}
const result = await Promise.all(ps);
return {
failedList,
result,
}
}
...@@ -17,7 +17,6 @@ import { ...@@ -17,7 +17,6 @@ import {
traverseViewNode traverseViewNode
} from "../../utils" } from "../../utils"
import {template} from "../../template" import {template} from "../../template"
import events from "@/global-events"
import {packAssetsGroups} from "../../utils/assets-pack" import {packAssetsGroups} from "../../utils/assets-pack"
import {addBehavior, deleteProcessMeta,} from "./behavior" import {addBehavior, deleteProcessMeta,} from "./behavior"
...@@ -26,6 +25,7 @@ import {preprocess} from "../../views/Preview/preview-preprocess" ...@@ -26,6 +25,7 @@ import {preprocess} from "../../views/Preview/preview-preprocess"
import {packageStore} from "./package" import {packageStore} from "./package"
import {toZeroing} from "psd-parse-web" import {toZeroing} from "psd-parse-web"
import {arrayFind} from "element-ui/src/utils/util"; import {arrayFind} from "element-ui/src/utils/util";
import {uploadFiles} from "./editor";
const storeName = 'project'; const storeName = 'project';
const psStoreName = 'pack-history'; const psStoreName = 'pack-history';
...@@ -619,7 +619,7 @@ export const projectStore = { ...@@ -619,7 +619,7 @@ export const projectStore = {
}, },
assetDepFlag: state => uuid => { assetDepFlag: state => uuid => {
return state.data.views.filter(view => return state.data.views.filter(view =>
view.explicitDepAssets.includes(uuid) || view.implicitDepAssets.includes(uuid) view.explicitDepAssets && view.explicitDepAssets.includes(uuid) || view.implicitDepAssets && view.implicitDepAssets.includes(uuid)
).length > 0 ? 0 : -1; ).length > 0 ? 0 : -1;
}, },
customs(state) { customs(state) {
...@@ -907,6 +907,7 @@ export const projectStore = { ...@@ -907,6 +907,7 @@ export const projectStore = {
return failedList; return failedList;
}, },
async replaceAsset({commit}, {uuid, file}) { async replaceAsset({commit}, {uuid, file}) {
console.log(file);
const {failedList, result} = await uploadFiles([file]); const {failedList, result} = await uploadFiles([file]);
commit('replaceAsset', {uuid, url: result[0].url,}); commit('replaceAsset', {uuid, url: result[0].url,});
return failedList; return failedList;
...@@ -971,34 +972,6 @@ export const projectStore = { ...@@ -971,34 +972,6 @@ export const projectStore = {
}, },
}; };
async function uploadFiles(files) {
const failedList = [];
let ps = [];
for (let file of files) {
events.$emit('upload-indicator', true);
ps.push(
editorApi.uploadFile(file).catch(e => {
failedList.push(file);
}).finally(() => {
events.$emit('upload-indicator', false);
})
);
}
const result = await Promise.all(ps);
return {
failedList,
result,
}
}
export async function updateMock(mocks) {
await db.clear('mock');
for (let mock of mocks) {
db.set('mock', mock);
}
}
function getDefaultOptions() { function getDefaultOptions() {
return clonePureObj(defaultOptions) return clonePureObj(defaultOptions)
...@@ -1040,3 +1013,10 @@ function copyBaseRoot(node) { ...@@ -1040,3 +1013,10 @@ function copyBaseRoot(node) {
} }
return data return data
} }
export async function updateMock(mocks) {
await db.clear('mock');
for (let mock of mocks) {
db.set('mock', mock);
}
}
...@@ -426,6 +426,61 @@ export function deleteAssetsDepConfig(data) { ...@@ -426,6 +426,61 @@ export function deleteAssetsDepConfig(data) {
} }
} }
export function formatJson(source){ export function formatJson(source) {
return source ? JSON.stringify(JSON.parse(source), null, '\t') : ''; return source ? JSON.stringify(JSON.parse(source), null, '\t') : '';
} }
let transCanvas = document.createElement('canvas');
export async function transPngToJpg(img, type = 'blob', option) {
const quality = option ? option.quality : 70;
const bgColor = option ? option.bgColor : '#FFFFFF';
if (!img) {
return;
}
let imgOrigin;
if (typeof img === 'string') {
imgOrigin = new Image();
imgOrigin.crossOrigin = 'anonymous';
imgOrigin.src = img;
await new Promise((resolve, reject) => {
imgOrigin.onload = resolve;
imgOrigin.onerror = reject;
})
} else {
imgOrigin = img;
}
const {width, height} = imgOrigin;
transCanvas.width = width;
transCanvas.height = height;
let ctx = transCanvas.getContext('2d');
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, width, height);
ctx.drawImage(imgOrigin, 0, 0);
let dataUrl = transCanvas.toDataURL('image/jpeg', quality / 100);
let result;
switch (type) {
case 'img':
let imgR = new Image();
imgR.src = dataUrl;
result = imgR;
break;
case 'blob':
result = dataURLtoBlob(dataUrl);
break;
}
return result;
}
export function dataURLtoBlob(dataUrl) {
var arr = dataUrl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type: mime});
}
...@@ -131,6 +131,26 @@ export default { ...@@ -131,6 +131,26 @@ export default {
type: 'color', type: 'color',
default: '#000' default: '#000'
}, },
shadowBlur: {
alias: '阴影模糊度',
type: 'string',
default: 0
},
shadowColor: {
alias: '阴影颜色',
type: 'color',
default: '#000'
},
shadowOffsetX: {
alias: '阴影偏移X',
type: 'number',
default: 0
},
shadowOffsetY: {
alias: '阴影偏移Y',
type: 'number',
default: 0
},
stroke: { stroke: {
alias: '描边宽度', alias: '描边宽度',
type: 'number', type: 'number',
......
...@@ -7,17 +7,21 @@ ...@@ -7,17 +7,21 @@
@click="onClickItem(asset, $event)" @click="onClickItem(asset, $event)"
@delete="onDeleteItem(asset)" @delete="onDeleteItem(asset)"
@combine="onCombineAssets" @combine="onCombineAssets"
@to-jpg="onToJpg"
/> />
<trans-to-jpg-option-dialog ref="transToJpgOptionDialog" @confirm="onConfirmToTransJpg"/>
</div> </div>
</template> </template>
<script> <script>
import {mapGetters, mapMutations} from 'vuex'; import {mapGetters, mapMutations, mapActions} from 'vuex';
import FileItem from "./FileItem"; import FileItem from "./FileItem";
import {transPngToJpg} from "../../../utils";
import TransToJpgOptionDialog from "./TransToJpgOptionDialog";
export default { export default {
name: "AssetList", name: "AssetList",
components: {FileItem}, components: {TransToJpgOptionDialog, FileItem},
props: { props: {
editable: { editable: {
type: Boolean, type: Boolean,
...@@ -105,6 +109,18 @@ ...@@ -105,6 +109,18 @@
}).catch((e) => { }).catch((e) => {
}); });
}, },
async onToJpg(asset) {
this.lastAsset = asset;
this.$refs.transToJpgOptionDialog.show();
},
async onConfirmToTransJpg(option){
let asset = this.lastAsset;
let blob = await transPngToJpg(asset.url, 'blob', option);
this.replaceAsset({
uuid: asset.uuid,
file: new File([blob], asset.name + '.jpg'),
});
},
selectItem(asset, unselectAll = true) { selectItem(asset, unselectAll = true) {
if (unselectAll) { if (unselectAll) {
this.selectedIndices.splice(0); this.selectedIndices.splice(0);
...@@ -140,6 +156,7 @@ ...@@ -140,6 +156,7 @@
return flag; return flag;
}, },
...mapMutations(['combineAssets']), ...mapMutations(['combineAssets']),
...mapActions(['replaceAsset']),
} }
} }
</script> </script>
......
...@@ -22,7 +22,9 @@ ...@@ -22,7 +22,9 @@
:command="key" :command="key"
:key="key" :key="key"
:disabled="key === 'combine' && !combinable" :disabled="key === 'combine' && !combinable"
>{{item}}</el-dropdown-item> v-if="showMenuItem(key)"
>{{item}}
</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
...@@ -68,9 +70,7 @@ ...@@ -68,9 +70,7 @@
assetItemMenu: this.$t('assetItemMenu'), assetItemMenu: this.$t('assetItemMenu'),
} }
}, },
watch: { watch: {},
},
computed: { computed: {
fileIcon() { fileIcon() {
let icon = fileTypeIcon[this.data.ext]; let icon = fileTypeIcon[this.data.ext];
...@@ -91,9 +91,9 @@ ...@@ -91,9 +91,9 @@
ellipsisName() { ellipsisName() {
return strEllipsis(this.data.name, 14, 5); return strEllipsis(this.data.name, 14, 5);
}, },
depFlag(){ depFlag() {
return this.$parent.getDepFlag(this.data.uuid); return this.$parent.getDepFlag(this.data.uuid);
} },
}, },
methods: { methods: {
onDbclick() { onDbclick() {
...@@ -126,6 +126,9 @@ ...@@ -126,6 +126,9 @@
case 'combine': case 'combine':
this.$emit('combine', this.data); this.$emit('combine', this.data);
break; break;
case 'to-jpg':
this.$emit('to-jpg', this.data);
break;
} }
}, },
editName() { editName() {
...@@ -151,6 +154,14 @@ ...@@ -151,6 +154,14 @@
}); });
}) })
}, },
showMenuItem(key) {
const {ext} = this.data;
if (key === 'to-jpg') {
return ext === '.png';
} else {
return true;
}
},
...mapMutations([ ...mapMutations([
'deleteAsset', 'deleteAsset',
'modifyAsset', 'modifyAsset',
......
<template>
<el-dialog :title="$t('Transform options')" width="70%" :visible.sync="visible" @opened="onOpen"
:append-to-body="true"
custom-class="flex-dialog details-dialog"
>
<el-form v-model="option" label-position="right" label-width="100px" size="mini" style="padding: 20px">
<el-form-item label="品质">
<el-input-number v-model="option.quality" :max="100" :min="10" controls-position="right"/>
</el-form-item>
<el-form-item label="底色">
<el-color-picker v-model="option.bgColor"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<div></div>
<div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
<el-button size="mini" @click="onConfirm" type="primary">{{$t('Confirm')}}</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import {mapMutations} from 'vuex';
import ElFormItem from "../../../components/inputs/form-item";
export default {
name: "TransToJpgOptionDialog",
components: {ElFormItem},
data() {
return {
visible: false,
option: {
quality: 70,
bgColor: '#ffffff',
}
}
},
methods: {
show() {
this.option.quality = 70;
this.option.bgColor = '#ffffff';
this.visible = true;
},
onConfirm() {
this.$emit('confirm', this.option);
this.visible = false;
},
onClose() {
this.visible = false;
},
onOpen() {
},
...mapMutations([
'modifyProjectDetails',
]),
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment