diff --git a/package/cpp/api/JsiSkImage.h b/package/cpp/api/JsiSkImage.h index c4019f5071..90581e9eb7 100644 --- a/package/cpp/api/JsiSkImage.h +++ b/package/cpp/api/JsiSkImage.h @@ -64,23 +64,32 @@ class JsiSkImage : public JsiSkWrappingSkPtrHostObject { std::make_shared(getContext(), std::move(shader))); } - JSI_HOST_FUNCTION(encodeToBytes) { + sk_sp encodeImageData(const jsi::Value *arguments, size_t count) { // Get optional parameters auto format = count >= 1 ? static_cast(arguments[0].asNumber()) : SkEncodedImageFormat::kPNG; - auto quality = count == 2 ? arguments[1].asNumber() : 100.0; - // Get data + auto quality = count == 2 ? arguments[1].asNumber() : 100.0; + auto image = getObject(); + if (image->isTextureBacked()) { + image = image->makeNonTextureImage(); + } sk_sp data; if (format == SkEncodedImageFormat::kJPEG) { SkJpegEncoder::Options options; options.fQuality = quality; - data = SkJpegEncoder::Encode(nullptr, getObject().get(), options); + data = SkJpegEncoder::Encode(nullptr, image.get(), options); } else { SkPngEncoder::Options options; - data = SkPngEncoder::Encode(nullptr, getObject().get(), options); + data = SkPngEncoder::Encode(nullptr, image.get(), options); } + return data; + } + + JSI_HOST_FUNCTION(encodeToBytes) { + auto data = encodeImageData(arguments, count); + auto arrayCtor = runtime.global().getPropertyAsFunction(runtime, "Uint8Array"); size_t size = data->size(); @@ -99,25 +108,8 @@ class JsiSkImage : public JsiSkWrappingSkPtrHostObject { } JSI_HOST_FUNCTION(encodeToBase64) { - // Get optional parameters - auto format = - count >= 1 ? static_cast(arguments[0].asNumber()) - : SkEncodedImageFormat::kPNG; + auto data = encodeImageData(arguments, count); - auto quality = count == 2 ? arguments[1].asNumber() : 100.0; - auto image = getObject(); - if (image->isTextureBacked()) { - image = image->makeNonTextureImage(); - } - sk_sp data; - if (format == SkEncodedImageFormat::kJPEG) { - SkJpegEncoder::Options options; - options.fQuality = quality; - data = SkJpegEncoder::Encode(nullptr, image.get(), options); - } else { - SkPngEncoder::Options options; - data = SkPngEncoder::Encode(nullptr, image.get(), options); - } auto len = SkBase64::Encode(data->bytes(), data->size(), nullptr); auto buffer = std::string(len, 0); SkBase64::Encode(data->bytes(), data->size(), diff --git a/package/src/renderer/__tests__/e2e/DataEncoding.spec.tsx b/package/src/renderer/__tests__/e2e/DataEncoding.spec.tsx new file mode 100644 index 0000000000..e1f3e1f2d3 --- /dev/null +++ b/package/src/renderer/__tests__/e2e/DataEncoding.spec.tsx @@ -0,0 +1,75 @@ +import { importSkia, surface } from "../setup"; + +describe("Data Encoding", () => { + it("encodeToBytes() from CPU image", async () => { + const result = await surface.eval((Skia) => { + const data = Skia.Data.fromBase64( + "R0lGODlhAQABAIAAAGGqHwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" + ); + const img = Skia.Image.MakeImageFromEncoded(data); + if (!img) { + return []; + } + return Array.from(img.encodeToBytes()); + }); + const { Skia } = importSkia(); + const data = Skia.Data.fromBase64( + "R0lGODlhAQABAIAAAGGqHwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" + ); + const img = Skia.Image.MakeImageFromEncoded(data)!; + expect(img).toBeTruthy(); + expect(result).toEqual(Array.from(img.encodeToBytes())); + }); + it("encodeToBase64() from CPU image", async () => { + const result = await surface.eval((Skia) => { + const data = Skia.Data.fromBase64( + "R0lGODlhAQABAIAAAGGqHwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" + ); + const img = Skia.Image.MakeImageFromEncoded(data); + if (!img) { + return ""; + } + return img.encodeToBase64(); + }); + const { Skia } = importSkia(); + + const data = Skia.Data.fromBase64( + "R0lGODlhAQABAIAAAGGqHwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" + ); + const img = Skia.Image.MakeImageFromEncoded(data)!; + expect(img).toBeTruthy(); + expect(result).toEqual(img.encodeToBase64()); + }); + it("encodeToBytes() from GPU image", async () => { + const result = await surface.eval((Skia) => { + const data = Skia.Data.fromBase64( + "R0lGODlhAQABAIAAAGGqHwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" + ); + const img = Skia.Image.MakeImageFromEncoded(data); + if (!img) { + return []; + } + const offscreen = Skia.Surface.MakeOffscreen(1, 1)!; + const canvas = offscreen.getCanvas(); + canvas.drawImage(img, 0, 0); + return Array.from(offscreen.makeImageSnapshot().encodeToBytes()); + }); + expect(result.length).toBeGreaterThan(0); + }); + it("encodeToBase64() from GPU image", async () => { + const result = await surface.eval((Skia) => { + const data = Skia.Data.fromBase64( + "R0lGODlhAQABAIAAAGGqHwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" + ); + const img = Skia.Image.MakeImageFromEncoded(data); + if (!img) { + return ""; + } + const offscreen = Skia.Surface.MakeOffscreen(1, 1)!; + const canvas = offscreen.getCanvas(); + canvas.drawImage(img, 0, 0); + return offscreen.makeImageSnapshot().encodeToBase64(); + }); + expect(result.length).toBeGreaterThan(0); + }); +});