From 0c5c1c61d35fd30a7cbb533bacb2b6399e16a5f1 Mon Sep 17 00:00:00 2001 From: Justin Georgi Date: Sun, 10 Nov 2024 19:52:08 -0700 Subject: [PATCH] Collect metadata from glb file Signed-off-by: Justin Georgi --- extension.json | 9 +++ i18n/en.json | 6 ++ includes/GlModelHandler.php | 94 +++++++++++++++++++++++++++++ includes/GlModelHooks.php | 12 +++- includes/GlModelTransformOutput.php | 2 +- modules/glmv-upl.js | 4 ++ modules/glmv.js | 2 +- 7 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 i18n/en.json diff --git a/extension.json b/extension.json index 41eb754..a55c5dc 100644 --- a/extension.json +++ b/extension.json @@ -23,6 +23,11 @@ "ExtensionMessagesFiles": { "GlModelHandlerMagic": "GlModelHandler.i18n.magic.php" }, + "MessagesDirs": { + "GlModelViewer": [ + "i18n" + ] + }, "ResourceFileModulePaths": { "localBasePath": "modules", "remoteExtPath": "GlModelViewer/modules" @@ -37,12 +42,16 @@ ], "dependencies": [ "mediawiki.util", + "mediawiki.storage", "mediawiki.api" ] }, "ext.glmv.upl": { "styles": [ "glmv-upl.css" + ], + "dependencies": [ + "mediawiki.storage" ], "packageFiles": [ "glmv-upl.js" diff --git a/i18n/en.json b/i18n/en.json new file mode 100644 index 0000000..06dd8b7 --- /dev/null +++ b/i18n/en.json @@ -0,0 +1,6 @@ +{ + "exif-glmv-meshes": "Number of meshes", + "exif-glmv-textures": "Number of textures", + "exif-glmv-version": "GLTF version", + "exif-glmv-generator": "Model generator" +} \ No newline at end of file diff --git a/includes/GlModelHandler.php b/includes/GlModelHandler.php index 5707e35..9d0b764 100644 --- a/includes/GlModelHandler.php +++ b/includes/GlModelHandler.php @@ -5,6 +5,8 @@ use ImageHandler; use Html; class GlModelHandler extends ImageHandler { + private const glmvVersion = '0.1'; + /** * Model cannot be displayed directly in a browser but can be rendered. * @@ -120,6 +122,7 @@ class GlModelHandler extends ImageHandler { /** * Get an associative array mapping magic word IDs to parameter names. + * * @return string[] */ public function getParamMap() { @@ -130,6 +133,97 @@ class GlModelHandler extends ImageHandler { ]; } + + /** + * This is used to generate an array element for each metadata value. That array is then used to generate the table of metadata values on the image page. + * + * @param array &$array An array containing elements for each type of visibility and each of those elements being an array of metadata items. This function adds a value to that array. + * @param string $visibility ('visible' or 'collapsed') if this value is hidden by default. + * @param string $type Type of metadata tag (currently always 'exif') + * @param string $id The name of the metadata tag (like 'artist' for example). its name in the table displayed is the message "$type-$id" (Ex exif-artist ). + * @param string $value Thingy goes into a wikitext table; it used to be escaped but that was incompatible with previous practise of customized display with wikitext formatting via messages such as 'exif-model-value'. So the escaping is taken back out, but generally this seems a confusing interface. + * @param bool | string $param Value to pass to the message for the name of the field as $1. Currently this parameter doesn't seem to ever be used. + */ + //public static function addMeta (&$array, $visibility, $type, $id, $value, $param = false ) { + // $array[$visibility][] = [ + // 'id' => "$type-$id", + // 'name' => $name, + // 'value' => $value + // ]; + //} + + + /** + * Get image size information and metadata array. + * + * @param MediaHandlerState $state An object for + * saving process-local state. This is normally a + * File object which will be passed back to other + * MediaHandler methods like pageCount(), if they + * are called in the same request. The handler + * can use this object to save its state. + * @param string $path The filename + * + * @return array|null Null to fall back to + * getImageSize(), or an array with width, height, + * bits, and metadata keys. All keys are optional. + */ + public function getSizeAndMetadata ($state, $path) { + + $gltf = fopen($path, 'r'); + fseek($gltf,12); + $glMetaLength = unpack("Iint", fread($gltf, 4)); + fseek($gltf,20); + $glMeta = json_decode(fread($gltf,$glMetaLength['int']),true); + fclose($gltf); + $newMeta = array( + 'Type' => $glType + ); + foreach($glMeta['asset'] as $key => $value) { + switch ($key) { + case 'author': + $newMeta['Author'] = $value; + break; + case 'copyright': + $newMeta['Copyright'] = $value; + break; + case 'generator': + $newMeta['glmv-generator'] = $value; + break; + case 'version': + $newMeta['glmv-version'] = $value; + break; + } + } + $newMeta['glmv-meshes'] = count($glMeta['meshes']); + $newMeta['glmv-textures'] = count($glMeta['textures']); + $newMeta['glmv-metadata'] = self::glmvVersion; + return array( + 'width' => 600, + 'height' => 800, + 'metadata' => $newMeta + ); + } + + /** + * Check if the metadata is valid for this handler. + * + * If it returns MediaHandler::METADATA_BAD (or false), Image will reload the metadata from the file and update the database. + * MediaHandler::METADATA_GOOD for if the metadata is a-ok, + * MediaHandler::METADATA_COMPATIBLE if metadata is old but backwards compatible (which may or may not trigger a metadata reload). + * + * TODO: This version is for testing/dev only. Better checking will be requried in the future + * @param File $image + * @return bool|int + */ + public function isFileMetadataValid ($image) { + $meta = $image->getMetadataItems('glmv-metadata'); + if (!isset($meta['glmv-metadata']) || $meta['glmv-metadata'] != self::glmvVersion) { + return self::METADATA_BAD; + } + return self::METADATA_GOOD; + } + /** * Small helper function to display information on the browser console * diff --git a/includes/GlModelHooks.php b/includes/GlModelHooks.php index 0af73f2..34e0171 100644 --- a/includes/GlModelHooks.php +++ b/includes/GlModelHooks.php @@ -42,9 +42,17 @@ class GlModelHooks { * @param OutputPage $out compiled page html and manipulation methods */ public static function onBeforePageDisplay($out) { - preg_match('/(getHTML(),$findGltf); + $file = MediaWikiServices::getInstance()->getRepoGroup()->findFile($out->getTitle()); + if ($file) { + echo ''; + } + preg_match('/(getHTML(),$findGltf); if ($findGltf[0]) { - $out->addHeadItems( + + $out->addHeadItems( Html::rawElement( 'script', array( diff --git a/includes/GlModelTransformOutput.php b/includes/GlModelTransformOutput.php index 9595b67..46ba449 100644 --- a/includes/GlModelTransformOutput.php +++ b/includes/GlModelTransformOutput.php @@ -143,7 +143,7 @@ class GlModelTransformOutput extends MediaTransformOutput { //Add important additional attributes and render model-viewer with hotspots $attrModelView = array_merge(['src' => $srcUrl, 'class' => 'mv-model', 'interpolation-decay' => '100', 'interaction-prompt' => 'none'], $attrModelView); $attrModelView['style'] = 'width: 100%; height: 100%;'; - $attrModelView['onload'] = 'modelLoaded()'; + $attrModelView['onload'] = 'modelLoaded(event)'; $hotspotHtml = (isset($hotspots)) ? implode($hotspots) : ''; $elModel = Html::rawElement('model-viewer', $attrModelView, $hotspotHtml); diff --git a/modules/glmv-upl.js b/modules/glmv-upl.js index a3ef9e2..d0d8615 100644 --- a/modules/glmv-upl.js +++ b/modules/glmv-upl.js @@ -10,6 +10,10 @@ checkForGltf = function (e) { const mvPreview = document.createElement('model-viewer') mvPreview.style['width'] = '180px' mvPreview.style['height'] = '180px' + mvPreview.addEventListener('load',(e) => { + mw.storage.session.set( 'mw_glbMeta', JSON.stringify($(e.target.originalGltfJson.asset))) + }, + {once: true}) const dThumbCap = document.createElement('div') dThumbCap.classList.add('thumbcaption') diff --git a/modules/glmv.js b/modules/glmv.js index a82d954..61207af 100644 --- a/modules/glmv.js +++ b/modules/glmv.js @@ -7,7 +7,7 @@ let currentSet = 'default' * Disables hiding of various child items * once model has loaded */ -modelLoaded = function() { +modelLoaded = function(e) { $('.awaiting-model').css('display', 'flex').removeClass('awaiting-model') if (typeof enableMenu != 'undefined') {enableMenu()} }