Skip to content

Commit 72d9b76

Browse files
committed
Use light WebP library rather than Skia
1 parent 286eb92 commit 72d9b76

29 files changed

Lines changed: 1308 additions & 38 deletions

PasteIntoFile.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.28729.10
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PasteIntoFile", "PasteIntoFile\PasteIntoFile.csproj", "{F6F4215C-6CD7-4279-9C4C-C2DA9A823D0C}"
77
EndProject
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebP", "WebP\WebP.csproj", "{D0BAB316-8DF0-4955-8B5A-E4909402A906}"
9+
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1012
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
1517
{F6F4215C-6CD7-4279-9C4C-C2DA9A823D0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
1618
{F6F4215C-6CD7-4279-9C4C-C2DA9A823D0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
1719
{F6F4215C-6CD7-4279-9C4C-C2DA9A823D0C}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{D0BAB316-8DF0-4955-8B5A-E4909402A906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{D0BAB316-8DF0-4955-8B5A-E4909402A906}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{D0BAB316-8DF0-4955-8B5A-E4909402A906}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{D0BAB316-8DF0-4955-8B5A-E4909402A906}.Release|Any CPU.Build.0 = Release|Any CPU
1824
EndGlobalSection
1925
GlobalSection(SolutionProperties) = preSolution
2026
HideSolutionNode = FALSE

PasteIntoFile/ClipboardContents.cs

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
using PasteIntoFile.Properties;
1717
using PdfSharp.Drawing;
1818
using PdfSharp.Pdf;
19-
using SkiaSharp;
19+
using WebP;
2020

2121
namespace PasteIntoFile {
2222

@@ -186,20 +186,17 @@ public override void SaveAs(string path, string extension, bool append = false)
186186
if (image == null)
187187
throw new FormatException(string.Format(Resources.str_error_cliboard_format_missmatch, extension));
188188

189-
var stream = new MemoryStream();
190-
image.Save(stream, image.RawFormat);
191-
stream.Position = 0;
192189

193190
switch (NormalizeExtension(extension)) {
194191
case "webp":
195-
//SKImage.FromEncodedData(stream).Encode(SKEncodedImageFormat.Webp, 90).SaveTo(File.OpenWrite(path));
196-
var webp = SKBitmap.Decode(stream).PeekPixels().Encode(new SKWebpEncoderOptions(SKWebpEncoderCompression.Lossless, 100));
197-
using (var fs = new FileStream(path, FileMode.Create)) {
198-
webp.SaveTo(fs);
199-
return;
200-
}
192+
var bytes = new WebPObject(image).GetWebPLossless();
193+
File.WriteAllBytes(path, bytes);
194+
return;
201195
case "pdf":
202196
// convert image to ximage
197+
var stream = new MemoryStream();
198+
image.Save(stream, image.RawFormat);
199+
stream.Position = 0;
203200
XImage img = XImage.FromStream(stream);
204201
// create pdf document
205202
PdfDocument document = new PdfDocument();
@@ -235,10 +232,12 @@ public override PreviewHolder Preview(string extension) {
235232
// Special formats with intermediate conversion types
236233
switch (extension) {
237234
case "pdf":
238-
case "webp":
239235
// Use png as intermediate format
240236
extension = "png";
241237
break;
238+
case "webp":
239+
// Lossless as-is
240+
return PreviewHolder.ForImage(Image);
242241
case "ico":
243242
return PreviewHolder.ForImage(ImageAsIcon.ToBitmap());
244243
}
@@ -300,7 +299,8 @@ public TransparentImageContent(Image image) : base(image) { }
300299
/// Like ImageContent, but only for formats which support animated frames
301300
/// </summary>
302301
public class AnimatedImageContent : ImageContent {
303-
public static new readonly string[] EXTENSIONS = { "gif" }; // TODO: in principle "webp" can also support animated frames
302+
// TODO: in principle "webp" can also support animated frames, but the library we use doesn't support it
303+
public static new readonly string[] EXTENSIONS = { "gif" };
304304
public AnimatedImageContent(Image image) : base(image) { }
305305
public override string[] Extensions => EXTENSIONS;
306306
}
@@ -1008,31 +1008,9 @@ public static ClipboardContents FromFile(string path) {
10081008
// add the file itself
10091009
container.Contents.Add(new FilesContent(new StringCollection { path }));
10101010

1011-
// if it's an image (try&catch instead of maintaining a list of supported extensions)
1012-
try {
1013-
var img = Image.FromFile(path);
1014-
img = RotateFlipImageFromExif(img);
1015-
if (img is Metafile mf) {
1016-
container.Contents.Add(new VectorImageContent(mf));
1017-
} else {
1018-
container.Contents.Add(new ImageContent(img));
1019-
}
1020-
} catch {
1021-
// Try again with Skia (to support webp)
1022-
try {
1023-
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) {
1024-
var img = SKBitmap.Decode(fs);
1025-
using (var stream = img.PeekPixels().Encode(SKPngEncoderOptions.Default).AsStream()) {
1026-
if (img.AlphaType == SKAlphaType.Opaque) {
1027-
container.Contents.Add(new ImageContent(Image.FromStream(stream)));
1028-
} else {
1029-
// TODO: FIXME: transparency seems to get lost during conversion
1030-
container.Contents.Add(new TransparentImageContent(Image.FromStream(stream)));
1031-
}
1032-
}
1033-
}
1034-
} catch { /* it's not */ }
1035-
}
1011+
// if it's an image
1012+
if (ImageContentFromBytes(ext, File.ReadAllBytes(path)) is BaseContent content)
1013+
container.Contents.Add(content);
10361014

10371015

10381016
// if it's text like (check for absence of zero byte)
@@ -1114,6 +1092,38 @@ private static Image ImageFromDataUri(string uri) {
11141092
return null;
11151093
}
11161094

1095+
private static ImageLikeContent ImageContentFromBytes(string ext, byte[] bytes) {
1096+
try {
1097+
if (ext == "webp") {
1098+
var webp = new WebPObject(bytes);
1099+
var img = new Bitmap(webp.GetImage()); // create copy
1100+
if (webp.GetInfo().IsAnimated)
1101+
return new AnimatedImageContent(img);
1102+
if (webp.GetInfo().HasAlpha)
1103+
return new TransparentImageContent(img);
1104+
return new ImageContent(img);
1105+
}
1106+
} catch (Exception e) { /* not a webp, or an animated webp which we don't support yet */
1107+
Console.WriteLine(e);
1108+
}
1109+
try {
1110+
var img = Image.FromStream(new MemoryStream(bytes));
1111+
img = RotateFlipImageFromExif(img);
1112+
if (img is Metafile mf)
1113+
return new VectorImageContent(mf);
1114+
try {
1115+
if (img.GetFrameCount(FrameDimension.Time) > 1)
1116+
return new AnimatedImageContent(img);
1117+
} catch { /* not an animated image */ }
1118+
if (((ImageFlags)img.Flags).HasFlag(ImageFlags.HasAlpha))
1119+
return new TransparentImageContent(img);
1120+
return new ImageContent(img);
1121+
} catch (Exception e) { /* not an image? */
1122+
Console.WriteLine(e);
1123+
}
1124+
return null;
1125+
}
1126+
11171127
/// <summary>
11181128
/// Rotates and flips the given image according to the respective EXIF flag, and remove the EXIF flag
11191129
/// </summary>

PasteIntoFile/PasteIntoFile.csproj

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<StartupObject>PasteIntoFile.Program</StartupObject>
1313
<ApplicationManifest>app.manifest</ApplicationManifest>
1414
<ApplicationIcon>Resources/icon.ico</ApplicationIcon>
15+
<LangVersion>12</LangVersion>
1516
</PropertyGroup>
1617
<!-- Build variants -->
1718
<PropertyGroup>
@@ -53,7 +54,6 @@
5354
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
5455
<PackageReference Include="PDFsharp" Version="1.50.5147" />
5556
<PackageReference Include="SharpClipboard" Version="3.5.2" />
56-
<PackageReference Include="SkiaSharp" Version="3.116.1" />
5757
</ItemGroup>
5858
<ItemGroup Condition="'$(Flavor)'=='Portable'">
5959
<PackageReference Include="PortableSettingsProvider" Version="0.2.4" />
@@ -157,6 +157,12 @@
157157
<EmbedInteropTypes>True</EmbedInteropTypes>
158158
</COMReference>
159159
</ItemGroup>
160+
<ItemGroup>
161+
<ProjectReference Include="..\WebP\WebP.csproj">
162+
<Project>{20e1114b-c211-46e5-a2e0-10a598ff4a44}</Project>
163+
<Name>WebP</Name>
164+
</ProjectReference>
165+
</ItemGroup>
160166
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
161167
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
162168
Other similar extension points exist, see Microsoft.Common.targets.

WebP/Helpers/ThrowHelper.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using System.Data;
3+
using System.Diagnostics.CodeAnalysis;
4+
using System.Runtime.CompilerServices;
5+
6+
namespace WebP.Helpers;
7+
8+
internal static class ThrowHelper {
9+
[Obsolete]
10+
public static Exception Create(
11+
Exception inner,
12+
[CallerMemberName] string caller = "Unknown") {
13+
return new Exception($"{inner.Message}\nIn {caller}", inner);
14+
}
15+
16+
public static Exception UnknownPlatform() {
17+
return new PlatformNotSupportedException("Unknown platform detected. Platform must be x86 or x64");
18+
}
19+
20+
[Obsolete]
21+
public static Exception ContainsNoData([CallerMemberName] string caller = "Unknown") {
22+
return Create(new DataException("Bitmap contains no data"), caller);
23+
}
24+
25+
[Obsolete]
26+
public static Exception SizeTooBig([CallerMemberName] string caller = "Unknown") {
27+
return
28+
Create(new DataException($"Dimension of bitmap is too large. Max is {WebPObject.WebpMaxDimension}x{WebPObject.WebpMaxDimension} pixels"),
29+
caller);
30+
}
31+
32+
[Obsolete]
33+
public static Exception CannotEncodeByUnknown([CallerMemberName] string caller = "Unknown") {
34+
return Create(new Exception("Cannot encode by unknown cause"), caller);
35+
}
36+
37+
[Obsolete]
38+
public static Exception NullReferenced(string var, [CallerMemberName] string caller = "Unknown") {
39+
return Create(new NullReferenceException($"{var} is null"), caller);
40+
}
41+
42+
[Obsolete]
43+
public static Exception QualityOutOfRange([CallerMemberName] string caller = "Unknown") {
44+
return Create(new NullReferenceException("Quality must be between"), caller);
45+
}
46+
}

WebP/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Sharp0802
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace WebP.Natives.Enums;
2+
3+
public enum Vp8StatusCode {
4+
Ok,
5+
OutOfMemory,
6+
InvalidParam,
7+
BitstreamError,
8+
UnsupportedFeature,
9+
Suspended,
10+
UserAbort,
11+
NotEnoughData
12+
}

WebP/Natives/Enums/WebPCspMode.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace WebP.Natives.Enums;
2+
3+
public enum WebpCspMode {
4+
ModeRgb,
5+
ModeRgba,
6+
ModeBgr,
7+
ModeBgra,
8+
9+
ModeARGB,
10+
ModeRGBA4444,
11+
ModeRGB565,
12+
13+
ModeRgbA,
14+
ModeBgrA,
15+
16+
ModeArgb,
17+
ModeRgbA4444,
18+
ModeYuv,
19+
20+
ModeYuva,
21+
ModeLast
22+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace WebP.Natives.Enums;
2+
3+
public enum WebPImageHint {
4+
Default,
5+
Picture,
6+
Photo,
7+
Graph,
8+
Last
9+
}

WebP/Natives/Enums/WebPPreset.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace WebP.Natives.Enums;
2+
3+
public enum WebPPreset {
4+
Default,
5+
Picture,
6+
Photo,
7+
Drawing,
8+
Icon,
9+
Text
10+
}

0 commit comments

Comments
 (0)