CesiumGS / gltf-pipeline

Content pipeline tools for optimizing glTF assets. :globe_with_meridians:
Apache License 2.0
1.87k stars 241 forks source link

Special characters in filenames cause incorrect operation #642

Open zhangjiuyi opened 10 months ago

zhangjiuyi commented 10 months ago

Version: 4.1.0

Issue Description:

I have a GLB file that, when uploaded and viewed for textures on the [BabylonJS Sandbox](https://sandbox.babylonjs.com/) and subsequently exported (as GLB), results in the internal texture names being renamed to the format blob:https:__sandbox image.png. This poses a problem when I use the command gltf-pipeline -i xxx.glb -t -o xx.gltf.

On macOS, filenames containing the : character get replaced with /, which leads to an error when running gltf-pipeline -i output.gltf -o output.glb, as the actual filename doesn't match the one inside the .gltf file. However, this can be manually fixed by adjusting the .gltf file itself.

On Windows, executing gltf-pipeline -i xxx.glb -t -o xx.gltf results in an error: (node:2128) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, open 'C:\Users\test\Desktop\glb\blob:https:__sandbox image_3.png’.

The probable cause seems to be the incompatibility of the : character with the Windows file system.

Expected Result:

I'd like the process to handle glb file unpacking and packing smoothly, even when filenames contain special characters.

Possible Solution:

I attempted to access the source code:

In bin/gltf-pipeline.js, I adjusted the saveSeparateResources method:

tsxCopy code
if (Object.prototype.hasOwnProperty.call(separateResources, relativePath)) {
  const resource = separateResources[relativePath];

  // Replace special characters
  const dirname = path.dirname(relativePath);
  const basename = path.basename(relativePath).replace(/[<>:"/\\|?*#]/g, '_');
  const sanitizedPath = path.join(dirname, basename);

  const resourcePath = path.join(outputDirectory, sanitizedPath);
  resourcePromises.push(fsExtra.outputFile(resourcePath, resource));
}

I also made changes in lib/addPipelineExtras.js:

tsxCopy code
//before
function addPipelineExtras(gltf) {
  ForEach.shader(gltf, function (shader) {
    addExtras(shader);
  });
  ForEach.buffer(gltf, function (buffer) {
    addExtras(buffer);
  });
  ForEach.image(gltf, function (image) {
    addExtras(image);
  });

  addExtras(gltf);

  return gltf;
}

// after
function addPipelineExtras(gltf) {
  ForEach.shader(gltf, function (shader) {
    addExtras(shader);
  });
  ForEach.buffer(gltf, function (buffer) {
    addExtras(buffer);
  });
  ForEach.image(gltf, function (image) {
    if (image.name) {
      image.name = image.name.replace(/[<>:"/\\|?*#]/g, '_');
    }
    addExtras(image);
  });

  addExtras(gltf);

  return gltf;
}

This approach provisionally addressed the issues I encountered. Perhaps another potential solution could be to use the encodeURIComponent(fileName) and decode method? But who's to say?