Skip to content

Commit aa856ed

Browse files
committed
feat: support gif
1 parent be5b48a commit aa856ed

1 file changed

Lines changed: 57 additions & 11 deletions

File tree

app/components/image/image-uploader.vue

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,20 +136,63 @@ async function submit() {
136136
return
137137
submitting.value = true
138138
try {
139-
const blob = await new Promise<Blob>((resolve, reject) => {
140-
cropper.value?.getCropBlob((blob: Blob | null) => {
141-
if (blob) {
142-
resolve(blob)
139+
const formData = new FormData()
140+
const isGif = fileRaw.value.type === 'image/gif'
141+
const fileName = fileRaw.value?.name ?? 'image.png'
142+
143+
if (isGif) {
144+
const getCropAxisData = await new Promise<string | object>((resolve, reject) => {
145+
if (!cropper.value) {
146+
reject(new Error('裁切器未初始化'))
147+
return
143148
}
144-
else {
145-
reject(new Error('Failed to crop image'))
149+
cropper.value.getCropAxis((axis: string | object) => resolve(axis))
150+
})
151+
152+
let x = 0; let y = 0; let w = 0; let h = 0
153+
154+
if (typeof getCropAxisData === 'string') {
155+
const axisParts = getCropAxisData.split(',').map(Number)
156+
if (axisParts.length >= 4 && !axisParts.some(isNaN)) {
157+
x = axisParts[0] || 0
158+
y = axisParts[1] || 0
159+
w = axisParts[2] || 0
160+
h = axisParts[3] || 0
146161
}
162+
}
163+
else if (typeof getCropAxisData === 'object' && getCropAxisData !== null) {
164+
const axisObj = getCropAxisData as any
165+
x = axisObj.x || 0
166+
y = axisObj.y || 0
167+
w = axisObj.width || 0
168+
h = axisObj.height || 0
169+
}
170+
171+
formData.append('crop_x', String(Math.floor(x)))
172+
formData.append('crop_y', String(Math.floor(y)))
173+
formData.append('crop_w', String(Math.floor(w)))
174+
formData.append('crop_h', String(Math.floor(h)))
175+
176+
formData.append('file', fileRaw.value, fileName)
177+
}
178+
else {
179+
const blob = await new Promise<Blob>((resolve, reject) => {
180+
if (!cropper.value) {
181+
reject(new Error('裁切器未初始化'))
182+
return
183+
}
184+
cropper.value.getCropBlob((blob: Blob | null) => {
185+
if (blob) {
186+
resolve(blob)
187+
}
188+
else {
189+
reject(new Error('Failed to crop image'))
190+
}
191+
})
147192
})
148-
})
193+
formData.append('file', blob, fileName)
194+
}
149195
150-
const formData = new FormData()
151-
const fileName = fileRaw.value?.name ?? 'image.png'
152-
formData.append('file', blob, fileName)
153196
formData.append('aspect_id', props.aspect.id)
154197
formData.append('name', metadata.name.trim())
155198
formData.append('description', metadata.description.trim() ?? metadata.name.trim())
@@ -204,13 +247,16 @@ async function submit() {
204247
<ClientOnly>
205248
<div class="rounded-lg border h-64 md:h-80 lg:h-96 w-full overflow-hidden">
206249
<VueCropper
207-
ref="cropper" :img="filePreviewImage" output-type="png" :auto-crop="true" :fixed="true"
250+
ref="cropperRef" :img="filePreviewImage" output-type="png" :auto-crop="true" :fixed="true"
208251
:fixed-number="cropRatio" :center-box="false" :auto-crop-width="cropBox.width"
209252
:auto-crop-height="cropBox.height" :full="true" :can-scale="true" :info-true="true"
210253
class="h-64 md:h-80 lg:h-96 w-full"
211254
/>
212255
</div>
213256
</ClientOnly>
257+
<div v-if="fileRaw?.type === 'image/gif'" class="alert alert-info py-2 shadow-sm text-sm">
258+
<span>检测到 GIF 动图。预览区将只显示静态帧,但上传成功后在展示处将保留动画效果。</span>
259+
</div>
214260
<div class="flex flex-wrap gap-2">
215261
<button class="btn btn-sm" type="button" @click="rotateLeft">
216262
⟲ 向左旋转

0 commit comments

Comments
 (0)