From 0c5c1c61d35fd30a7cbb533bacb2b6399e16a5f1 Mon Sep 17 00:00:00 2001 From: Justin Georgi Date: Sun, 10 Nov 2024 19:52:08 -0700 Subject: [PATCH 1/3] 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()} } From 9e1f89b92b8579143ac1224e1f3ca1a176091678 Mon Sep 17 00:00:00 2001 From: Justin Georgi Date: Mon, 11 Nov 2024 20:35:08 -0700 Subject: [PATCH 2/3] Enable metadata versioning Signed-off-by: Justin Georgi --- includes/GlModelHandler.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/includes/GlModelHandler.php b/includes/GlModelHandler.php index 9d0b764..ebc1096 100644 --- a/includes/GlModelHandler.php +++ b/includes/GlModelHandler.php @@ -2,10 +2,11 @@ namespace MediaWiki\Extension\GlModelViewer; use ImageHandler; +use BitmapMetadataHandler; use Html; class GlModelHandler extends ImageHandler { - private const glmvVersion = '0.1'; + private const GLMV_VERSION = '0.2'; /** * Model cannot be displayed directly in a browser but can be rendered. @@ -169,7 +170,6 @@ class GlModelHandler extends ImageHandler { * 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)); @@ -177,7 +177,8 @@ class GlModelHandler extends ImageHandler { $glMeta = json_decode(fread($gltf,$glMetaLength['int']),true); fclose($gltf); $newMeta = array( - 'Type' => $glType + 'glmv-meshes' => count($glMeta['meshes']), + 'glmv-textures' => count($glMeta['textures']) ); foreach($glMeta['asset'] as $key => $value) { switch ($key) { @@ -195,9 +196,9 @@ class GlModelHandler extends ImageHandler { break; } } - $newMeta['glmv-meshes'] = count($glMeta['meshes']); - $newMeta['glmv-textures'] = count($glMeta['textures']); - $newMeta['glmv-metadata'] = self::glmvVersion; + $newMeta['glmv-metadata'] = self::GLMV_VERSION; + $metaHandler = new BitmapMetadataHandler; + $metaHandler->addMetadata($newMeta,'exif'); return array( 'width' => 600, 'height' => 800, @@ -212,13 +213,13 @@ class GlModelHandler extends ImageHandler { * 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 + * TODO: This version is for testing/dev only. Better checking will be required 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) { + $meta = $image->getMetadataItems(['glmv-metadata']); + if (!isset($meta['glmv-metadata']) || $meta['glmv-metadata'] != self::GLMV_VERSION) { return self::METADATA_BAD; } return self::METADATA_GOOD; From d559e786d1674fe476d71b2e1e448544b3a94720 Mon Sep 17 00:00:00 2001 From: Justin Georgi Date: Mon, 11 Nov 2024 20:55:07 -0700 Subject: [PATCH 3/3] Display metadata on file page Signed-off-by: Justin Georgi --- i18n/en.json | 3 ++- includes/GlModelHandler.php | 22 +++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/i18n/en.json b/i18n/en.json index 06dd8b7..13a4e8c 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -2,5 +2,6 @@ "exif-glmv-meshes": "Number of meshes", "exif-glmv-textures": "Number of textures", "exif-glmv-version": "GLTF version", - "exif-glmv-generator": "Model generator" + "exif-glmv-generator": "Model generator", + "exif-glmv-metadata": "GLMV metadata version" } \ No newline at end of file diff --git a/includes/GlModelHandler.php b/includes/GlModelHandler.php index ebc1096..6243498 100644 --- a/includes/GlModelHandler.php +++ b/includes/GlModelHandler.php @@ -198,7 +198,7 @@ class GlModelHandler extends ImageHandler { } $newMeta['glmv-metadata'] = self::GLMV_VERSION; $metaHandler = new BitmapMetadataHandler; - $metaHandler->addMetadata($newMeta,'exif'); + $metaHandler->addMetadata($newMeta,'native'); return array( 'width' => 600, 'height' => 800, @@ -225,6 +225,26 @@ class GlModelHandler extends ImageHandler { return self::METADATA_GOOD; } + /** + * Get an array structure that the UI will format this into a table where the visible + * fields are always visible, and the collapsed fields are optionally visible. + * + * The function should return false if there is no metadata to display. + * + * @param File $image + * @param bool|IContextSource $context Context to use (optional) + * @return bool|array + */ + public function formatMetadata( $image, $context = false ) { + $glmvMetadata = $image->getMetadataArray(); + + if (!count( $glmvMetadata ) ) { + return false; + } else { + return $this->formatMetadataHelper( $glmvMetadata, $context ); + } + } + /** * Small helper function to display information on the browser console *