mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 11:28:24 +00:00 
			
		
		
		
	Add support for 3D/CAD file formats preview (#34794)
Fix #34775 --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		| @@ -1,17 +0,0 @@ | ||||
| import {htmlEscape} from 'escape-goat'; | ||||
| import {registerGlobalInitFunc} from '../modules/observer.ts'; | ||||
|  | ||||
| export async function initPdfViewer() { | ||||
|   registerGlobalInitFunc('initPdfViewer', async (el: HTMLInputElement) => { | ||||
|     const pdfobject = await import(/* webpackChunkName: "pdfobject" */'pdfobject'); | ||||
|  | ||||
|     const src = el.getAttribute('data-src'); | ||||
|     const fallbackText = el.getAttribute('data-fallback-button-text'); | ||||
|     pdfobject.embed(src, el, { | ||||
|       fallbackLink: htmlEscape` | ||||
|         <a role="button" class="ui basic button pdf-fallback-button" href="[url]">${fallbackText}</a> | ||||
|       `, | ||||
|     }); | ||||
|     el.classList.remove('is-loading'); | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										10
									
								
								web_src/js/render/plugin.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								web_src/js/render/plugin.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| export type FileRenderPlugin = { | ||||
|   // unique plugin name | ||||
|   name: string; | ||||
|  | ||||
|   // test if plugin can handle a specified file | ||||
|   canHandle: (filename: string, mimeType: string) => boolean; | ||||
|  | ||||
|   // render file content | ||||
|   render: (container: HTMLElement, fileUrl: string, options?: any) => Promise<void>; | ||||
| } | ||||
							
								
								
									
										60
									
								
								web_src/js/render/plugins/3d-viewer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								web_src/js/render/plugins/3d-viewer.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| import type {FileRenderPlugin} from '../plugin.ts'; | ||||
| import {extname} from '../../utils.ts'; | ||||
|  | ||||
| // support common 3D model file formats, use online-3d-viewer library for rendering | ||||
|  | ||||
| // eslint-disable-next-line multiline-comment-style | ||||
| /* a simple text STL file example: | ||||
| solid SimpleTriangle | ||||
|   facet normal 0 0 1 | ||||
|     outer loop | ||||
|       vertex 0 0 0 | ||||
|       vertex 1 0 0 | ||||
|       vertex 0 1 0 | ||||
|     endloop | ||||
|   endfacet | ||||
| endsolid SimpleTriangle | ||||
| */ | ||||
|  | ||||
| export function newRenderPlugin3DViewer(): FileRenderPlugin { | ||||
|   // Some extensions are text-based formats: | ||||
|   // .3mf .amf .brep: XML | ||||
|   // .fbx: XML or BINARY | ||||
|   // .dae .gltf: JSON | ||||
|   // .ifc, .igs, .iges, .stp, .step are: TEXT | ||||
|   // .stl .ply: TEXT or BINARY | ||||
|   // .obj .off .wrl: TEXT | ||||
|   // So we need to be able to render when the file is recognized as plaintext file by backend. | ||||
|   // | ||||
|   // It needs more logic to make it overall right (render a text 3D model automatically): | ||||
|   // we need to distinguish the ambiguous filename extensions. | ||||
|   // For example: "*.obj, *.off, *.step" might be or not be a 3D model file. | ||||
|   // So when it is a text file, we can't assume that "we only render it by 3D plugin", | ||||
|   // otherwise the end users would be impossible to view its real content when the file is not a 3D model. | ||||
|   const SUPPORTED_EXTENSIONS = [ | ||||
|     '.3dm', '.3ds', '.3mf', '.amf', '.bim', '.brep', | ||||
|     '.dae', '.fbx', '.fcstd', '.glb', '.gltf', | ||||
|     '.ifc', '.igs', '.iges', '.stp', '.step', | ||||
|     '.stl', '.obj', '.off', '.ply', '.wrl', | ||||
|   ]; | ||||
|  | ||||
|   return { | ||||
|     name: '3d-model-viewer', | ||||
|  | ||||
|     canHandle(filename: string, _mimeType: string): boolean { | ||||
|       const ext = extname(filename).toLowerCase(); | ||||
|       return SUPPORTED_EXTENSIONS.includes(ext); | ||||
|     }, | ||||
|  | ||||
|     async render(container: HTMLElement, fileUrl: string): Promise<void> { | ||||
|       // TODO: height and/or max-height? | ||||
|       const OV = await import(/* webpackChunkName: "online-3d-viewer" */'online-3d-viewer'); | ||||
|       const viewer = new OV.EmbeddedViewer(container, { | ||||
|         backgroundColor: new OV.RGBAColor(59, 68, 76, 0), | ||||
|         defaultColor: new OV.RGBColor(65, 131, 196), | ||||
|         edgeSettings: new OV.EdgeSettings(false, new OV.RGBColor(0, 0, 0), 1), | ||||
|       }); | ||||
|       viewer.LoadModelFromUrlList([fileUrl]); | ||||
|     }, | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										20
									
								
								web_src/js/render/plugins/pdf-viewer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								web_src/js/render/plugins/pdf-viewer.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| import type {FileRenderPlugin} from '../plugin.ts'; | ||||
|  | ||||
| export function newRenderPluginPdfViewer(): FileRenderPlugin { | ||||
|   return { | ||||
|     name: 'pdf-viewer', | ||||
|  | ||||
|     canHandle(filename: string, _mimeType: string): boolean { | ||||
|       return filename.toLowerCase().endsWith('.pdf'); | ||||
|     }, | ||||
|  | ||||
|     async render(container: HTMLElement, fileUrl: string): Promise<void> { | ||||
|       const PDFObject = await import(/* webpackChunkName: "pdfobject" */'pdfobject'); | ||||
|       // TODO: the PDFObject library does not support dynamic height adjustment, | ||||
|       container.style.height = `${window.innerHeight - 100}px`; | ||||
|       if (!PDFObject.default.embed(fileUrl, container)) { | ||||
|         throw new Error('Unable to render the PDF file'); | ||||
|       } | ||||
|     }, | ||||
|   }; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user