Skip to content

Commit 2aaeafb

Browse files
孙圣翔²⁰₂₁孙圣翔²⁰₂₁
孙圣翔²⁰₂₁
authored and
孙圣翔²⁰₂₁
committed
heic support
1 parent 0e68288 commit 2aaeafb

File tree

3 files changed

+93
-4
lines changed

3 files changed

+93
-4
lines changed

servefs/static/css/style.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,26 @@
8989
border-radius: 4px;
9090
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
9191
}
92+
93+
.heic-preview {
94+
position: relative;
95+
outline: none;
96+
text-align: center;
97+
display: flex;
98+
justify-content: center;
99+
align-items: center;
100+
min-height: 200px;
101+
max-height: 70vh;
102+
}
103+
104+
.heic-preview img {
105+
max-width: 100%;
106+
max-height: 70vh;
107+
border: 1px solid lightgray;
108+
border-radius: 4px;
109+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
110+
}
111+
92112
.video-preview {
93113
text-align: center;
94114
display: flex;

servefs/static/index.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ <h1>ServeFS File Browser</h1>
179179
<img :src="previewDialog.content" :alt="previewDialog.title">
180180
<el-icon class="preview-nav-button preview-next" @click="showNextImage" v-if="hasNextImage"><arrow-right /></el-icon>
181181
</div>
182+
<!-- HEIC图片预览 -->
183+
<div v-else-if="previewDialog.isHeic" class="heic-preview">
184+
<img :src="previewDialog.content" :alt="previewDialog.title">
185+
</div>
182186
<!-- 视频预览 -->
183187
<div v-else-if="previewDialog.isVideo" class="video-preview">
184188
<video controls :src="previewDialog.content">
@@ -262,7 +266,7 @@ <h1>ServeFS File Browser</h1>
262266
</template>
263267
</el-dialog>
264268
</div>
265-
269+
<script src="https://unpkg.com/heic2any@0.0.4/dist/heic2any.min.js"></script>
266270
<script src="/static/js/index.js"></script>
267271

268272
</body>

servefs/static/js/index.js

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const app = createApp({
1616
editable: false,
1717
currentFile: null,
1818
isImage: false,
19+
isHeic: false,
1920
isVideo: false,
2021
isText: false,
2122
isFont: false,
@@ -90,6 +91,11 @@ const app = createApp({
9091
return imageExtensions.some(ext => filename.toLowerCase().endsWith(ext));
9192
};
9293

94+
// 检查是否为HEIC/HEIF格式图片
95+
const isHeicImage = (filename) => {
96+
return filename.toLowerCase().endsWith('.heic') || filename.toLowerCase().endsWith('.heif');
97+
};
98+
9399
// 检查文件是否为视频
94100
const isVideoFile = (filename) => {
95101
const videoExtensions = ['.mp4', '.webm', '.ogg', '.mov', '.mkv', '.avi'];
@@ -112,6 +118,7 @@ const app = createApp({
112118
editable: type === 'text',
113119
currentFile: item,
114120
isImage: type === 'image',
121+
isHeic: type === 'heic',
115122
isVideo: type === 'video',
116123
isText: type === 'text',
117124
isFont: type === 'font',
@@ -122,9 +129,49 @@ const app = createApp({
122129
};
123130
};
124131

132+
// 处理HEIC图片预览
133+
const handleHeicPreview = async (item) => {
134+
// Show loading message
135+
ElMessage({
136+
message: 'Converting HEIC image...',
137+
type: 'info',
138+
duration: 0
139+
});
140+
141+
try {
142+
// Fetch the HEIC file
143+
const response = await fetch(`/raw/${item.path}`);
144+
const blob = await response.blob();
145+
146+
// Convert HEIC to JPEG
147+
const jpegBlob = await heic2any({
148+
blob: blob,
149+
toType: "image/jpeg",
150+
quality: 0.8
151+
});
152+
153+
// Create object URL for the converted image
154+
const imageUrl = URL.createObjectURL(jpegBlob);
155+
156+
// Close loading message
157+
ElMessage.closeAll();
158+
159+
return {
160+
...createPreviewConfig(item, 'heic'),
161+
content: imageUrl
162+
};
163+
} catch (error) {
164+
ElMessage.error('Failed to convert HEIC image');
165+
console.error('HEIC conversion error:', error);
166+
throw error;
167+
}
168+
};
169+
125170
const openFile = async (item) => {
126171
try {
127-
if (isImageFile(item.name)) {
172+
if (isHeicImage(item.name)) {
173+
previewDialog.value = await handleHeicPreview(item);
174+
} else if (isImageFile(item.name)) {
128175
previewDialog.value = createPreviewConfig(item, 'image');
129176
} else if (isVideoFile(item.name)) {
130177
previewDialog.value = createPreviewConfig(item, 'video');
@@ -459,12 +506,30 @@ const app = createApp({
459506
};
460507

461508
// 更新预览图片
462-
const updatePreviewImage = (image, index) => {
509+
const updatePreviewImage = async (image, index) => {
463510
if (image) {
464511
previewDialog.value.currentImageIndex = index;
465512
previewDialog.value.title = image.name;
466-
previewDialog.value.content = `/raw/${image.path}`;
467513
previewDialog.value.currentFile = image;
514+
515+
if (isHeicImage(image.name)) {
516+
try {
517+
const previewConfig = await handleHeicPreview(image);
518+
previewDialog.value = {
519+
...previewConfig,
520+
currentImageIndex: index
521+
};
522+
} catch (error) {
523+
// If HEIC conversion fails, fall back to raw path
524+
previewDialog.value = {
525+
...createPreviewConfig(image, 'heic'),
526+
content: `/raw/${image.path}`,
527+
currentImageIndex: index
528+
};
529+
}
530+
} else {
531+
previewDialog.value.content = `/raw/${image.path}`;
532+
}
468533
}
469534
};
470535

0 commit comments

Comments
 (0)