Spaces:
Running
Running
Download src/preview.ts from fffiloni/openusd-explorer: direct link, hf CLI and curl.
- Browser
- Download file 2.45 kB
-
https://huggingface.co/spaces/fffiloni/openusd-explorer/resolve/main/src/preview.ts
- Command line
-
hf download hf://spaces/fffiloni/openusd-explorer/src/preview.ts
-
curl -L -o preview.ts https://huggingface.co/spaces/fffiloni/openusd-explorer/resolve/main/src/preview.ts
2.45 kB
| import type {Asset} from './types.ts'; | |
| /** Repository file listings can be truncated. Only a failed image request, | |
| * not absence from that listing, means a thumbnail is unavailable. | |
| * Also upgrades catalogues generated by earlier app versions. | |
| */ | |
| export function previewSources(asset:Pick<Asset,'image'|'imageFallback'|'preview'>):string[]{ | |
| const prepared=asset.preview?[asset.preview]:[]; | |
| const url=new URL(asset.image); | |
| if(!url.pathname.endsWith('.png'))return [...new Set([...prepared,asset.image,asset.imageFallback])]; | |
| const base=url.pathname.replace(/(?:_(?:transparent|light))?\.png$/,''); | |
| const variants=['_transparent.png','_light.png','.png'].map(suffix=>{ | |
| const candidate=new URL(url);candidate.pathname=base+suffix;return candidate.href; | |
| }); | |
| return [...new Set([...prepared,...variants,asset.imageFallback,asset.image])]; | |
| } | |
| /** Read native alpha bounds without altering colors or transparency. | |
| * Opaque previews retain their background; color-keying them can destroy | |
| * dark details and leave baked shadows behind. Antialiased edges stay intact. | |
| */ | |
| export function alphaBounds(data:Uint8ClampedArray,width:number,height:number){ | |
| let left=width,right=-1,top=height,bottom=-1; | |
| for(let y=0;y<height;y++)for(let x=0;x<width;x++)if(data[(y*width+x)*4+3]>0){ | |
| left=Math.min(left,x);right=Math.max(right,x);top=Math.min(top,y);bottom=Math.max(bottom,y); | |
| } | |
| return right<left||bottom<top?null:{left,top,width:right-left+1,height:bottom-top+1}; | |
| } | |
| export function normalizePreview(image:HTMLImageElement):string|null{ | |
| try{ | |
| const canvas=document.createElement('canvas');canvas.width=image.naturalWidth;canvas.height=image.naturalHeight; | |
| if(canvas.width>2048||canvas.height>2048)return null; | |
| const context=canvas.getContext('2d',{willReadFrequently:true});if(!context)return null;context.drawImage(image,0,0); | |
| const pixels=context.getImageData(0,0,canvas.width,canvas.height); | |
| const bounds=alphaBounds(pixels.data,canvas.width,canvas.height);if(!bounds)return null; | |
| const output=document.createElement('canvas');output.width=output.height=320;const out=output.getContext('2d');if(!out)return null; | |
| out.imageSmoothingEnabled=true;out.imageSmoothingQuality='high'; | |
| const {left,top,width:w,height:h}=bounds,scale=292/Math.max(w,h); | |
| out.drawImage(canvas,left,top,w,h,(320-w*scale)/2,(320-h*scale)/2,w*scale,h*scale); | |
| return output.toDataURL('image/png'); | |
| }catch{return null;} | |
| } | |