Skip to content

Commit

Permalink
Merge pull request #1813 from qdraw/feature/202411_webp
Browse files Browse the repository at this point in the history
WebP support
  • Loading branch information
qdraw authored Nov 11, 2024
2 parents 88fb0c6 + a511cfa commit db82e17
Show file tree
Hide file tree
Showing 13 changed files with 854 additions and 685 deletions.
1 change: 1 addition & 0 deletions history.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Semantic Versioning 2.0.0 is from version 0.1.6+
- [x] (Fixed) _Front-end_ increase description limit (Issue #1810) (PR #1814)
- [x] (Fixed) _Back-end_ Change reading order to favor XMP for description/title field (PR #1814)
- [x] (Fixed) _Back-end_ OrderBy ImageFormat and then alphabet (PR #1815)
- [x] (Added) _Back-end_ WebP support for sync, reading & writing (PR #1813)

## version 0.6.2 - 2024-10-11 {#v0.6.2}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace starsky.foundation.platform.Helpers;
public static partial class ExtensionRolesHelper
{
/// <summary>
/// ImageFormat based on first bytes
/// ImageFormat based on first bytes, so read first bytes
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum ImageFormat
Expand All @@ -25,6 +25,7 @@ public enum ImageFormat
bmp = 13,
gif = 14,
png = 15,
webp = 16,

// Sidecar files
xmp = 30,
Expand Down Expand Up @@ -109,6 +110,11 @@ private static readonly List<string>
/// </summary>
private static readonly List<string> ExtensionMp4 = new() { "mp4", "mov" };

/// <summary>
/// WebP imageFormat
/// </summary>
private static readonly List<string> ExtensionWebp = new() { "webp" };

private static readonly Dictionary<ImageFormat, List<string>>
MapFileTypesToExtensionDictionary =
new()
Expand All @@ -120,7 +126,8 @@ private static readonly Dictionary<ImageFormat, List<string>>
{ ImageFormat.png, ExtensionPng },
{ ImageFormat.gpx, ExtensionGpx },
{ ImageFormat.mp4, ExtensionMp4 },
{ ImageFormat.xmp, ExtensionXmp }
{ ImageFormat.xmp, ExtensionXmp },
{ ImageFormat.webp, ExtensionWebp }
};

/// <summary>
Expand All @@ -141,6 +148,7 @@ public static List<string> ExtensionSyncSupportedList
extensionList.AddRange(ExtensionMp4);
extensionList.AddRange(ExtensionXmp);
extensionList.AddRange(ExtensionJsonSidecar);
extensionList.AddRange(ExtensionWebp);
return extensionList;
}
}
Expand All @@ -159,6 +167,7 @@ private static List<string> ExtensionExifToolSupportedList
extensionList.AddRange(ExtensionGif);
extensionList.AddRange(ExtensionPng);
extensionList.AddRange(ExtensionMp4);
extensionList.AddRange(ExtensionWebp);
return extensionList;
}
}
Expand All @@ -180,6 +189,7 @@ public static List<string> ExtensionThumbSupportedList
extensionList.AddRange(ExtensionBmp);
extensionList.AddRange(ExtensionGif);
extensionList.AddRange(ExtensionPng);
extensionList.AddRange(ExtensionWebp);
return extensionList;
}
}
Expand Down Expand Up @@ -441,7 +451,7 @@ private static byte[] ReadBuffer(Stream stream, int size)

/// <summary>
/// Get the format of the image by looking the first bytes
/// Stream is Flushed / Disposed afterwards
/// Stream is Flushed / Disposed afterward
/// </summary>
/// <param name="stream">stream</param>
/// <returns>ImageFormat enum</returns>
Expand Down Expand Up @@ -525,9 +535,30 @@ public static ImageFormat GetImageFormat(byte[] bytes)
return ImageFormat.meta_json;
}

if ( GetImageFormatMetaWebp(bytes) != null )
{
return ImageFormat.webp;
}

return ImageFormat.unknown;
}

private static ImageFormat? GetImageFormatMetaWebp(byte[] bytes)
{
var webpFirstPart = new byte[] { 82, 73, 70, 70 };
var webpSecondPart = new byte[] { 87, 69, 66, 80 };

var isFirstPart = webpFirstPart.SequenceEqual(bytes.Take(webpFirstPart.Length));
var isSecondPart = webpSecondPart.SequenceEqual(bytes.Skip(8).Take(webpSecondPart.Length));

if ( isFirstPart && isSecondPart )
{
return ImageFormat.webp;
}

return null;
}

private static ImageFormat? GetImageFormatMetaJson(byte[] bytes)
{
var metaJsonUnix = new byte[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,11 @@ private static ExtensionRolesHelper.ImageFormat GetFileSpecificTags(
return ExtensionRolesHelper.ImageFormat.gif;
}

if ( allExifItems.Exists(p => p.Name == "WebP") )
{
return ExtensionRolesHelper.ImageFormat.webp;
}

return ExtensionRolesHelper.ImageFormat.unknown;
}

Expand Down Expand Up @@ -565,13 +570,13 @@ private static string GetXmpData(Directory? exifItem, string propertyPath)
if ( !string.IsNullOrEmpty(xmpTitle) )
{
return xmpTitle;
}
}

var iptcDirectory = allExifItems.OfType<IptcDirectory>().FirstOrDefault();
var iptcObjectName = iptcDirectory?.Tags.FirstOrDefault(
p => p.Name == "Object Name")?.Description;
iptcObjectName ??= string.Empty;

return iptcObjectName;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const ListImage: React.FunctionComponent<IListImageProps> = memo((props) => {
props.imageFormat !== ImageFormat.bmp &&
props.imageFormat !== ImageFormat.gif &&
props.imageFormat !== ImageFormat.jpg &&
props.imageFormat !== ImageFormat.webp &&
props.imageFormat !== ImageFormat.png
) {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,10 @@ describe("PreferencesAppSettingsDesktop", () => {

await waitFor(() => {
const query =
"DefaultDesktopEditor%5B0%5D.ImageFormats%5B0%5D=jpg&DefaultDesktopEditor%5B0%5D.ImageFormats%" +
"5B1%5D=png&DefaultDesktopEditor%5B0%5D.ImageFormats%5B2%5D=bmp&DefaultDesktopEditor%5B0%5D.ImageFormats%5B3%5D=tiff&" +
"DefaultDesktopEditor%5B0%5D.ApplicationPath=test";
"DefaultDesktopEditor%5B0%5D.ImageFormats%5B0%5D=jpg&DefaultDesktopEditor%5B0%5D." +
"ImageFormats%5B1%5D=png&DefaultDesktopEditor%5B0%5D.ImageFormats%5B2%5D=bmp&" +
"DefaultDesktopEditor%5B0%5D.ImageFormats%5B3%5D=tiff&DefaultDesktopEditor%5B0%5D." +
"ImageFormats%5B4%5D=webp&DefaultDesktopEditor%5B0%5D.ApplicationPath=test";

expect(spyFetchPost).toHaveBeenCalledTimes(1);
expect(spyFetchPost).toHaveBeenCalledWith(new UrlQuery().UrlApiAppSettings(), query);
Expand Down Expand Up @@ -354,13 +355,15 @@ describe("updateDefaultEditorPhotos", () => {

expect(spyFetchPost).toHaveBeenCalled();
const query =
"DefaultDesktopEditor%5B0%5D.ImageFormats%5B0%5D=jpg&DefaultDesktopEditor%5B0%5D.ImageFormats%" +
"5B1%5D=png&DefaultDesktopEditor%5B0%5D.ImageFormats%5B2%5D=bmp&DefaultDesktopEditor%5B0%5D.ImageFormats%5B3%5D=tiff&" +
"DefaultDesktopEditor%5B0%5D.ApplicationPath=test";
"DefaultDesktopEditor%5B0%5D.ImageFormats%5B0%5D=jpg&DefaultDesktopEditor%5B0%5D.ImageFormats" +
"%5B1%5D=png&DefaultDesktopEditor%5B0%5D.ImageFormats%5B2%5D=bmp&DefaultDesktopEditor%5B0%5D." +
"ImageFormats%5B3%5D=tiff&DefaultDesktopEditor%5B0%5D.ImageFormats%5B4%5D=webp&DefaultDesktopEditor%5B0%5D." +
"ApplicationPath=test";

expect(spyFetchPost).toHaveBeenCalledWith(new UrlQuery().UrlApiAppSettings(), query);
});

it("Create new item in Array if emthy array", async () => {
it("should update existing editor and add new editor if array is not empty", async () => {
const value = {
target: { innerText: "test" }
} as unknown as ChangeEvent<HTMLDivElement>;
Expand Down Expand Up @@ -388,10 +391,14 @@ describe("updateDefaultEditorPhotos", () => {
expect(spyFetchPost).toHaveBeenCalled();

const query2 =
"DefaultDesktopEditor%5B0%5D.ImageFormats%5B0%5D=jpg&DefaultDesktopEditor%5B0%5D.ImageFormats%5B1%5D=png&DefaultDesktopEditor" +
"%5B0%5D.ImageFormats%5B2%5D=bmp&DefaultDesktopEditor%5B0%5D.ImageFormats%5B3%5D=tiff&DefaultDesktopEditor%5B0%5D.ApplicationPath=%2Fexist_app&" +
"DefaultDesktopEditor%5B1%5D.ImageFormats%5B0%5D=jpg&DefaultDesktopEditor%5B1%5D.ImageFormats%5B1%5D=png&DefaultDesktopEditor%5B1%5D.ImageFormats%5B2%5D=bmp&" +
"DefaultDesktopEditor%5B1%5D.ImageFormats%5B3%5D=tiff&DefaultDesktopEditor%5B1%5D.ApplicationPath=test";
"DefaultDesktopEditor%5B0%5D.ImageFormats%5B0%5D=jpg&DefaultDesktopEditor%5B0%5D." +
"ImageFormats%5B1%5D=png&DefaultDesktopEditor%5B0%5D.ImageFormats%5B2%5D=bmp&" +
"DefaultDesktopEditor%5B0%5D.ImageFormats%5B3%5D=tiff&" +
"DefaultDesktopEditor%5B0%5D.ImageFormats%5B4%5D=webp&DefaultDesktopEditor" +
"%5B0%5D.ApplicationPath=%2Fexist_app&DefaultDesktopEditor%5B1%5D.ImageFormats%5B0%5D=jpg" +
"&DefaultDesktopEditor%5B1%5D.ImageFormats%5B1%5D=png&DefaultDesktopEditor%5B1%5D.ImageFormats%5B2%5D=bmp" +
"&DefaultDesktopEditor%5B1%5D.ImageFormats%5B3%5D=tiff&DefaultDesktopEditor%5B1%5D.ImageFormats%5B4%5D=webp" +
"&DefaultDesktopEditor%5B1%5D.ApplicationPath=test";

expect(spyFetchPost).toHaveBeenCalledWith(new UrlQuery().UrlApiAppSettings(), query2);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ import FormControl from "../../atoms/form-control/form-control";
import SwitchButton from "../../atoms/switch-button/switch-button";

const defaultEditorApplication = {
imageFormats: [ImageFormat.jpg, ImageFormat.png, ImageFormat.bmp, ImageFormat.tiff]
imageFormats: [
ImageFormat.jpg,
ImageFormat.png,
ImageFormat.bmp,
ImageFormat.tiff,
ImageFormat.webp
]
} as IAppSettingsDefaultEditorApplication;

export async function UpdateDefaultEditorPhotos(
Expand Down
1 change: 1 addition & 0 deletions starsky/starsky/clientapp/src/interfaces/IFileIndexItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export enum ImageFormat {
bmp = "bmp",
gif = "gif",
png = "png",
webp = "webp",
xmp = "xmp",
meta_json = "meta_json",
gpx = "gpx",
Expand Down
Loading

1 comment on commit db82e17

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.