mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-27 09:45:13 +00:00
feat: use cloud backend thumbnail resize for image previews (#9298)
## Summary - In cloud mode, large generated images (4K, 8K+) cause browser freezing when loaded at full resolution for preview display - The cloud backend (ingest service) now supports a `res` query parameter on `/api/view` that returns server-side resized JPEG (quality 80, max 512px) instead of redirecting to the full-size GCS original - This PR adds `&res=512` to all image preview URLs in cloud mode, reducing browser decode overhead from tens of MB to tens of KB - Downloads still use the original resolution (no `res` param) - No impact on localhost/desktop builds (`isCloud` compile-time constant) ### without `?res` 302 -> png downloads <img width="808" height="564" alt="스크린샷 2026-02-28 오후 6 53 03" src="https://github.com/user-attachments/assets/7c1c62dd-0bc4-468d-9c74-7b98e892e126" /> <img width="323" height="137" alt="스크린샷 2026-02-28 오후 6 52 52" src="https://github.com/user-attachments/assets/926aa0c4-856c-4057-96a0-d8fbd846762b" /> 200 -> jpeg ### with `?res` <img width="811" height="407" alt="스크린샷 2026-02-28 오후 6 51 55" src="https://github.com/user-attachments/assets/d58d46ae-6749-4888-8bad-75344c4d868b" /> ### Changes - **New utility**: `getCloudResParam(filename?)` returns `&res=512` in cloud mode for image files, empty string otherwise - **Core stores**: `imagePreviewStore` appends `res` to node output URLs; `queueStore.ResultItemImpl` gets a `previewUrl` getter (separates preview from download URLs) - **Applied to**: asset browser thumbnails, widget dropdown previews, linear mode indicators, image compare node, background image upload ### Intentionally excluded - Downloads (`getAssetUrl`) — need original resolution - Mask editor — needs pixel-accurate data - Audio/video/3D files — `res` only applies to raster images - Execution-in-progress previews — use WebSocket blob URLs, not `/api/view` ## Test plan - [x] Unit tests for `getCloudResParam()` (5 tests: cloud/non-cloud, image/non-image, undefined filename) - [x] `pnpm typecheck` passes - [x] `pnpm lint` passes - [x] All 5332 unit tests pass - [x] Manual verification on cloud.comfy.org: `res=512` returns 200 with resized JPEG; without `res` returns 302 redirect to GCS PNG original --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import Button from '@/components/ui/button/Button.vue'
|
||||
import { extractVueNodeData } from '@/composables/graph/useGraphNodeManager'
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
|
||||
import { useBillingContext } from '@/composables/billing/useBillingContext'
|
||||
import { appendCloudResParam } from '@/platform/distribution/cloudPreviewUtil'
|
||||
import SubscribeToRunButton from '@/platform/cloud/subscription/components/SubscribeToRun.vue'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useTelemetry } from '@/platform/telemetry'
|
||||
@@ -88,13 +89,16 @@ function getDropIndicator(node: LGraphNode) {
|
||||
const filename = node.widgets?.[0]?.value
|
||||
const resultItem = { type: 'input', filename: `${filename}` }
|
||||
|
||||
const buildImageUrl = () => {
|
||||
if (!filename) return undefined
|
||||
const params = new URLSearchParams(resultItem)
|
||||
appendCloudResParam(params, String(filename))
|
||||
return api.apiURL(`/view?${params}${app.getPreviewFormatParam()}`)
|
||||
}
|
||||
|
||||
return {
|
||||
iconClass: 'icon-[lucide--image]',
|
||||
imageUrl: filename
|
||||
? api.apiURL(
|
||||
`/view?${new URLSearchParams(resultItem)}${app.getPreviewFormatParam()}`
|
||||
)
|
||||
: undefined,
|
||||
imageUrl: buildImageUrl(),
|
||||
label: t('linearMode.dragAndDropImage'),
|
||||
onClick: () => node.widgets?.[1]?.callback?.(undefined)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { computed, provide, ref, toRef, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { useTransformCompatOverlayProps } from '@/composables/useTransformCompatOverlayProps'
|
||||
import { appendCloudResParam } from '@/platform/distribution/cloudPreviewUtil'
|
||||
import { SUPPORTED_EXTENSIONS_ACCEPT } from '@/extensions/core/load3d/constants'
|
||||
import { useAssetFilterOptions } from '@/platform/assets/composables/useAssetFilterOptions'
|
||||
import {
|
||||
@@ -460,7 +461,9 @@ function getMediaUrl(
|
||||
type: 'input' | 'output' = 'input'
|
||||
): string {
|
||||
if (!['image', 'video'].includes(props.assetKind ?? '')) return ''
|
||||
return `/api/view?filename=${encodeURIComponent(filename)}&type=${type}`
|
||||
const params = new URLSearchParams({ filename, type })
|
||||
appendCloudResParam(params, filename)
|
||||
return `/api/view?${params}`
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user