mirror of
https://github.com/microsoft/PowerToys
synced 2025-08-22 10:07:37 +00:00
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [X] **Closes:** #30352 - [X] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [X] **Tests:** Added/updated and all pass - [X] **Localization:** All end user facing strings can be localized - [ ] **Dev docs:** Added/updated - [X] **New binaries:** Added on the required places - [X] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [X] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments   <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed - Close PowerToys if installed in your machine - Full build the solution: PowerToys.sln - Start PowerToys from PowerToys\x64\Debug\PowerToys.exe or PowerToys\x64\Release\PowerToys.exe - Toggle the "Binary G-code thumbnail previewer" setting to enable - Open HelperFiles folder on the tests and check if the icon changes to an image - Check explorer preview to see if image is also shown there --------- Co-authored-by: leileizhang <leilzh@microsoft.com>
130 lines
4.9 KiB
C#
130 lines
4.9 KiB
C#
// Copyright (c) Microsoft Corporation
|
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using System.Linq;
|
|
|
|
namespace Microsoft.PowerToys.FilePreviewCommon
|
|
{
|
|
/// <summary>
|
|
/// Bgcode file helper class.
|
|
/// </summary>
|
|
public static class BgcodeHelper
|
|
{
|
|
private const uint MagicNumber = 'G' | 'C' << 8 | 'D' << 16 | 'E' << 24;
|
|
|
|
/// <summary>
|
|
/// Gets any thumbnails found in a bgcode file.
|
|
/// </summary>
|
|
/// <param name="reader">The <see cref="BinaryReader"/> instance to the bgcode file.</param>
|
|
/// <returns>The thumbnails found in a bgcode file.</returns>
|
|
public static IEnumerable<BgcodeThumbnail> GetThumbnails(BinaryReader reader)
|
|
{
|
|
var magicNumber = reader.ReadUInt32();
|
|
|
|
if (magicNumber != MagicNumber)
|
|
{
|
|
throw new InvalidDataException("Invalid magic number.");
|
|
}
|
|
|
|
var version = reader.ReadUInt32();
|
|
|
|
if (version != 1)
|
|
{
|
|
// Version 1 is the only one that exists
|
|
throw new InvalidDataException("Unsupported version.");
|
|
}
|
|
|
|
var checksum = (BgcodeChecksumType)reader.ReadUInt16();
|
|
|
|
while (reader.BaseStream.Position < reader.BaseStream.Length)
|
|
{
|
|
var blockType = (BgcodeBlockType)reader.ReadUInt16();
|
|
var compression = (BgcodeCompressionType)reader.ReadUInt16();
|
|
var uncompressedSize = reader.ReadUInt32();
|
|
|
|
var size = compression == BgcodeCompressionType.NoCompression ? uncompressedSize : reader.ReadUInt32();
|
|
|
|
switch (blockType)
|
|
{
|
|
case BgcodeBlockType.FileMetadataBlock:
|
|
case BgcodeBlockType.PrinterMetadataBlock:
|
|
case BgcodeBlockType.PrintMetadataBlock:
|
|
case BgcodeBlockType.SlicerMetadataBlock:
|
|
case BgcodeBlockType.GCodeBlock:
|
|
reader.BaseStream.Seek(2 + size, SeekOrigin.Current); // Skip
|
|
|
|
break;
|
|
|
|
case BgcodeBlockType.ThumbnailBlock:
|
|
var format = (BgcodeThumbnailFormat)reader.ReadUInt16();
|
|
|
|
reader.BaseStream.Seek(4, SeekOrigin.Current); // Skip width and height
|
|
|
|
var data = ReadAndDecompressData(reader, compression, (int)size);
|
|
|
|
if (data != null)
|
|
{
|
|
yield return new BgcodeThumbnail(format, data);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (checksum == BgcodeChecksumType.CRC32)
|
|
{
|
|
reader.BaseStream.Seek(4, SeekOrigin.Current); // Skip checksum
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the best thumbnail available in a bgcode file.
|
|
/// </summary>
|
|
/// <param name="reader">The <see cref="BinaryReader"/> instance to the gcode file.</param>
|
|
/// <returns>The best thumbnail available in the gcode file.</returns>
|
|
public static BgcodeThumbnail? GetBestThumbnail(BinaryReader reader)
|
|
{
|
|
return GetThumbnails(reader)
|
|
.OrderByDescending(x => x.Format switch
|
|
{
|
|
BgcodeThumbnailFormat.PNG => 2,
|
|
BgcodeThumbnailFormat.QOI => 1,
|
|
BgcodeThumbnailFormat.JPG => 0,
|
|
_ => 0,
|
|
})
|
|
.ThenByDescending(x => x.Data.Length)
|
|
.FirstOrDefault();
|
|
}
|
|
|
|
private static byte[]? ReadAndDecompressData(BinaryReader reader, BgcodeCompressionType compression, int size)
|
|
{
|
|
// Though the spec doesn't actually mention it, the reference encoder code never applies compression to thumbnails data
|
|
// which makes complete sense as this data is PNG, JPEG or QOI encoded so already compressed as much as possible!
|
|
switch (compression)
|
|
{
|
|
case BgcodeCompressionType.NoCompression:
|
|
return reader.ReadBytes(size);
|
|
|
|
case BgcodeCompressionType.DeflateAlgorithm:
|
|
var buffer = new byte[size];
|
|
|
|
using (var deflateStream = new DeflateStream(reader.BaseStream, CompressionMode.Decompress, true))
|
|
{
|
|
deflateStream.ReadExactly(buffer, 0, size);
|
|
}
|
|
|
|
return buffer;
|
|
|
|
default:
|
|
reader.BaseStream.Seek(size, SeekOrigin.Current); // Skip unknown or unsupported compression types
|
|
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|