@shopify/react-native-skia 2.4.20 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/android/CMakeLists.txt +12 -49
  2. package/android/build.gradle +37 -1
  3. package/apple/MetalContext.h +2 -3
  4. package/apple/SkiaCVPixelBufferUtils.h +11 -8
  5. package/apple/SkiaCVPixelBufferUtils.mm +229 -49
  6. package/apple/SkiaUIView.mm +4 -0
  7. package/cpp/api/JsiSkColor.h +53 -1
  8. package/cpp/api/JsiSkContourMeasureIter.h +1 -1
  9. package/cpp/api/JsiSkFont.h +3 -1
  10. package/cpp/api/JsiSkFontStyle.h +3 -1
  11. package/cpp/api/JsiSkHostObjects.h +13 -1
  12. package/cpp/api/JsiSkImage.h +3 -0
  13. package/cpp/api/JsiSkImageInfo.h +3 -1
  14. package/cpp/api/JsiSkMatrix.h +3 -1
  15. package/cpp/api/JsiSkPaint.h +3 -1
  16. package/cpp/api/JsiSkPoint.h +3 -1
  17. package/cpp/api/JsiSkRRect.h +3 -1
  18. package/cpp/api/JsiSkRSXform.h +3 -1
  19. package/cpp/api/JsiSkRect.h +3 -1
  20. package/cpp/api/JsiSkRuntimeShaderBuilder.h +1 -1
  21. package/cpp/api/JsiSkSVGFactory.h +1 -1
  22. package/cpp/jsi2/NativeObject.h +6 -1
  23. package/cpp/rnwgpu/ArrayBuffer.h +7 -2
  24. package/lib/commonjs/renderer/Canvas.d.ts +2 -0
  25. package/lib/commonjs/renderer/Canvas.js +0 -3
  26. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  27. package/lib/commonjs/renderer/Offscreen.d.ts +3 -3
  28. package/lib/commonjs/renderer/Offscreen.js.map +1 -1
  29. package/lib/commonjs/skia/types/Image/Image.d.ts +2 -1
  30. package/lib/commonjs/skia/types/Image/Image.js.map +1 -1
  31. package/lib/commonjs/sksg/Container.native.js +3 -5
  32. package/lib/commonjs/sksg/Container.native.js.map +1 -1
  33. package/lib/module/renderer/Canvas.d.ts +2 -0
  34. package/lib/module/renderer/Canvas.js +0 -3
  35. package/lib/module/renderer/Canvas.js.map +1 -1
  36. package/lib/module/renderer/Offscreen.d.ts +3 -3
  37. package/lib/module/renderer/Offscreen.js.map +1 -1
  38. package/lib/module/skia/types/Image/Image.d.ts +2 -1
  39. package/lib/module/skia/types/Image/Image.js.map +1 -1
  40. package/lib/module/sksg/Container.native.js +3 -5
  41. package/lib/module/sksg/Container.native.js.map +1 -1
  42. package/lib/typescript/lib/commonjs/renderer/Offscreen.d.ts +2 -2
  43. package/lib/typescript/lib/module/renderer/Offscreen.d.ts +2 -2
  44. package/lib/typescript/src/renderer/Canvas.d.ts +2 -0
  45. package/lib/typescript/src/renderer/Offscreen.d.ts +3 -3
  46. package/lib/typescript/src/skia/types/Image/Image.d.ts +2 -1
  47. package/package.json +10 -30
  48. package/react-native-skia.podspec +110 -58
  49. package/src/renderer/Canvas.tsx +2 -3
  50. package/src/renderer/Offscreen.tsx +9 -3
  51. package/src/skia/types/Image/Image.ts +2 -1
  52. package/src/sksg/Container.native.ts +3 -4
  53. package/scripts/install-skia.mjs +0 -728
@@ -1 +1 @@
1
- {"version":3,"names":["Skia","Platform","SkiaSGRoot","isOnMainThread","_WORKLET","OS","drawAsPicture","element","bounds","recorder","PictureRecorder","canvas","beginRecording","root","render","drawOnCanvas","picture","finishRecordingAsPicture","dispose","unmount","drawAsImage","size","drawAsImageFromPicture","surface","Surface","MakeOffscreen","width","height","getCanvas","drawPicture","flush","image","makeImageSnapshot","makeNonTextureImage"],"sources":["Offscreen.tsx"],"sourcesContent":["import type { ReactElement } from \"react\";\n\nimport type { SkPicture, SkRect, SkSize } from \"../skia/types\";\nimport { Skia } from \"../skia\";\nimport { Platform } from \"../Platform\";\nimport { SkiaSGRoot } from \"../sksg/Reconciler\";\n\nexport const isOnMainThread = () => {\n \"worklet\";\n return (\n (typeof _WORKLET !== \"undefined\" && _WORKLET === true) ||\n Platform.OS === \"web\"\n );\n};\n\nexport const drawAsPicture = async (element: ReactElement, bounds?: SkRect) => {\n const recorder = Skia.PictureRecorder();\n const canvas = recorder.beginRecording(bounds);\n const root = new SkiaSGRoot(Skia);\n await root.render(element);\n root.drawOnCanvas(canvas);\n const picture = recorder.finishRecordingAsPicture();\n recorder.dispose();\n root.unmount();\n return picture;\n};\n\nexport const drawAsImage = async (element: ReactElement, size: SkSize) => {\n return drawAsImageFromPicture(await drawAsPicture(element), size);\n};\n\nexport const drawAsImageFromPicture = (picture: SkPicture, size: SkSize) => {\n \"worklet\";\n const surface = Skia.Surface.MakeOffscreen(size.width, size.height)!;\n const canvas = surface.getCanvas();\n canvas.drawPicture(picture);\n surface.flush();\n const image = surface.makeImageSnapshot();\n return image.makeNonTextureImage();\n};\n"],"mappings":"AAGA,SAASA,IAAI,QAAQ,SAAS;AAC9B,SAASC,QAAQ,QAAQ,aAAa;AACtC,SAASC,UAAU,QAAQ,oBAAoB;AAE/C,OAAO,MAAMC,cAAc,GAAGA,CAAA,KAAM;EAClC,SAAS;;EACT,OACG,OAAOC,QAAQ,KAAK,WAAW,IAAIA,QAAQ,KAAK,IAAI,IACrDH,QAAQ,CAACI,EAAE,KAAK,KAAK;AAEzB,CAAC;AAED,OAAO,MAAMC,aAAa,GAAG,MAAAA,CAAOC,OAAqB,EAAEC,MAAe,KAAK;EAC7E,MAAMC,QAAQ,GAAGT,IAAI,CAACU,eAAe,CAAC,CAAC;EACvC,MAAMC,MAAM,GAAGF,QAAQ,CAACG,cAAc,CAACJ,MAAM,CAAC;EAC9C,MAAMK,IAAI,GAAG,IAAIX,UAAU,CAACF,IAAI,CAAC;EACjC,MAAMa,IAAI,CAACC,MAAM,CAACP,OAAO,CAAC;EAC1BM,IAAI,CAACE,YAAY,CAACJ,MAAM,CAAC;EACzB,MAAMK,OAAO,GAAGP,QAAQ,CAACQ,wBAAwB,CAAC,CAAC;EACnDR,QAAQ,CAACS,OAAO,CAAC,CAAC;EAClBL,IAAI,CAACM,OAAO,CAAC,CAAC;EACd,OAAOH,OAAO;AAChB,CAAC;AAED,OAAO,MAAMI,WAAW,GAAG,MAAAA,CAAOb,OAAqB,EAAEc,IAAY,KAAK;EACxE,OAAOC,sBAAsB,CAAC,MAAMhB,aAAa,CAACC,OAAO,CAAC,EAAEc,IAAI,CAAC;AACnE,CAAC;AAED,OAAO,MAAMC,sBAAsB,GAAGA,CAACN,OAAkB,EAAEK,IAAY,KAAK;EAC1E,SAAS;;EACT,MAAME,OAAO,GAAGvB,IAAI,CAACwB,OAAO,CAACC,aAAa,CAACJ,IAAI,CAACK,KAAK,EAAEL,IAAI,CAACM,MAAM,CAAE;EACpE,MAAMhB,MAAM,GAAGY,OAAO,CAACK,SAAS,CAAC,CAAC;EAClCjB,MAAM,CAACkB,WAAW,CAACb,OAAO,CAAC;EAC3BO,OAAO,CAACO,KAAK,CAAC,CAAC;EACf,MAAMC,KAAK,GAAGR,OAAO,CAACS,iBAAiB,CAAC,CAAC;EACzC,OAAOD,KAAK,CAACE,mBAAmB,CAAC,CAAC;AACpC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["Skia","Platform","SkiaSGRoot","isOnMainThread","_WORKLET","OS","drawAsPicture","element","bounds","recorder","PictureRecorder","canvas","beginRecording","root","render","drawOnCanvas","picture","finishRecordingAsPicture","dispose","unmount","drawAsImage","size","drawAsImageFromPicture","surface","Surface","MakeOffscreen","width","height","getCanvas","drawPicture","flush","image","makeImageSnapshot","makeNonTextureImage"],"sources":["Offscreen.tsx"],"sourcesContent":["import type { ReactElement } from \"react\";\n\nimport type { SkImage, SkPicture, SkRect, SkSize } from \"../skia/types\";\nimport { Skia } from \"../skia\";\nimport { Platform } from \"../Platform\";\nimport { SkiaSGRoot } from \"../sksg/Reconciler\";\n\nexport const isOnMainThread = () => {\n \"worklet\";\n return (\n (typeof _WORKLET !== \"undefined\" && _WORKLET === true) ||\n Platform.OS === \"web\"\n );\n};\n\nexport const drawAsPicture = async (element: ReactElement, bounds?: SkRect) => {\n const recorder = Skia.PictureRecorder();\n const canvas = recorder.beginRecording(bounds);\n const root = new SkiaSGRoot(Skia);\n await root.render(element);\n root.drawOnCanvas(canvas);\n const picture = recorder.finishRecordingAsPicture();\n recorder.dispose();\n root.unmount();\n return picture;\n};\n\nexport const drawAsImage = async (\n element: ReactElement,\n size: SkSize\n): Promise<SkImage | null> => {\n return drawAsImageFromPicture(await drawAsPicture(element), size);\n};\n\nexport const drawAsImageFromPicture = (\n picture: SkPicture,\n size: SkSize\n): SkImage | null => {\n \"worklet\";\n const surface = Skia.Surface.MakeOffscreen(size.width, size.height)!;\n const canvas = surface.getCanvas();\n canvas.drawPicture(picture);\n surface.flush();\n const image = surface.makeImageSnapshot();\n return image.makeNonTextureImage();\n};\n"],"mappings":"AAGA,SAASA,IAAI,QAAQ,SAAS;AAC9B,SAASC,QAAQ,QAAQ,aAAa;AACtC,SAASC,UAAU,QAAQ,oBAAoB;AAE/C,OAAO,MAAMC,cAAc,GAAGA,CAAA,KAAM;EAClC,SAAS;;EACT,OACG,OAAOC,QAAQ,KAAK,WAAW,IAAIA,QAAQ,KAAK,IAAI,IACrDH,QAAQ,CAACI,EAAE,KAAK,KAAK;AAEzB,CAAC;AAED,OAAO,MAAMC,aAAa,GAAG,MAAAA,CAAOC,OAAqB,EAAEC,MAAe,KAAK;EAC7E,MAAMC,QAAQ,GAAGT,IAAI,CAACU,eAAe,CAAC,CAAC;EACvC,MAAMC,MAAM,GAAGF,QAAQ,CAACG,cAAc,CAACJ,MAAM,CAAC;EAC9C,MAAMK,IAAI,GAAG,IAAIX,UAAU,CAACF,IAAI,CAAC;EACjC,MAAMa,IAAI,CAACC,MAAM,CAACP,OAAO,CAAC;EAC1BM,IAAI,CAACE,YAAY,CAACJ,MAAM,CAAC;EACzB,MAAMK,OAAO,GAAGP,QAAQ,CAACQ,wBAAwB,CAAC,CAAC;EACnDR,QAAQ,CAACS,OAAO,CAAC,CAAC;EAClBL,IAAI,CAACM,OAAO,CAAC,CAAC;EACd,OAAOH,OAAO;AAChB,CAAC;AAED,OAAO,MAAMI,WAAW,GAAG,MAAAA,CACzBb,OAAqB,EACrBc,IAAY,KACgB;EAC5B,OAAOC,sBAAsB,CAAC,MAAMhB,aAAa,CAACC,OAAO,CAAC,EAAEc,IAAI,CAAC;AACnE,CAAC;AAED,OAAO,MAAMC,sBAAsB,GAAGA,CACpCN,OAAkB,EAClBK,IAAY,KACO;EACnB,SAAS;;EACT,MAAME,OAAO,GAAGvB,IAAI,CAACwB,OAAO,CAACC,aAAa,CAACJ,IAAI,CAACK,KAAK,EAAEL,IAAI,CAACM,MAAM,CAAE;EACpE,MAAMhB,MAAM,GAAGY,OAAO,CAACK,SAAS,CAAC,CAAC;EAClCjB,MAAM,CAACkB,WAAW,CAACb,OAAO,CAAC;EAC3BO,OAAO,CAACO,KAAK,CAAC,CAAC;EACf,MAAMC,KAAK,GAAGR,OAAO,CAACS,iBAAiB,CAAC,CAAC;EACzC,OAAOD,KAAK,CAACE,mBAAmB,CAAC,CAAC;AACpC,CAAC","ignoreList":[]}
@@ -125,6 +125,7 @@ export interface SkImage extends SkJSIInstance<"Image"> {
125
125
  * Returns raster image or lazy image. Copies SkImage backed by GPU texture
126
126
  * into CPU memory if needed. Returns original SkImage if decoded in raster
127
127
  * bitmap, or if encoded in a stream.
128
+ * Returns null if the conversion fails.
128
129
  */
129
- makeNonTextureImage(): SkImage;
130
+ makeNonTextureImage(): SkImage | null;
130
131
  }
@@ -1 +1 @@
1
- {"version":3,"names":["FilterMode","MipmapMode","ImageFormat","isCubicSampling","sampling","MitchellCubicSampling","B","C","CatmullRomCubicSampling","CubicSampling","MakeCubic"],"sources":["Image.ts"],"sourcesContent":["import type { SkMatrix } from \"../Matrix\";\nimport type { SkJSIInstance } from \"../JsiInstance\";\nimport type { TileMode } from \"../ImageFilter\";\nimport type { SkShader } from \"../Shader\";\n\nimport type { ImageInfo } from \"./ImageFactory\";\n\nexport interface CubicResampler {\n B: number;\n C: number;\n}\n\nexport interface FilterOptions {\n filter: FilterMode;\n mipmap?: MipmapMode;\n}\n\nexport enum FilterMode {\n Nearest,\n Linear,\n}\n\nexport enum MipmapMode {\n None,\n Nearest,\n Linear,\n}\n\nexport enum ImageFormat {\n JPEG = 3,\n PNG = 4,\n WEBP = 6,\n}\n\nexport type SamplingOptions = CubicResampler | FilterOptions;\n\nexport const isCubicSampling = (\n sampling: SamplingOptions\n): sampling is CubicResampler => {\n \"worklet\";\n return \"B\" in sampling && \"C\" in sampling;\n};\n\nexport const MitchellCubicSampling = { B: 1 / 3.0, C: 1 / 3.0 };\nexport const CatmullRomCubicSampling = { B: 0, C: 1 / 2.0 };\nexport const CubicSampling = { B: 0, C: 0 };\nexport const MakeCubic = (B: number, C: number) => ({ B, C });\n\nexport interface SkImage extends SkJSIInstance<\"Image\"> {\n /**\n * Returns the possibly scaled height of the image.\n */\n height(): number;\n\n /**\n * Returns the possibly scaled width of the image.\n */\n width(): number;\n\n /**\n * Returns the ImageInfo describing the image.\n */\n getImageInfo(): ImageInfo;\n\n /**\n * Returns the backend texture of the image.\n * The returned object can be used to create a Skia Image object.\n * The returned object is backend specific and should be used with caution.\n * It is the caller's responsibility to ensure that the texture is not used after the image is deleted.\n * The returned object may be null if the image does not have a backend texture.\n *\n * @return backend texture of the image or null\n */\n getNativeTextureUnstable(): unknown;\n\n /**\n * Returns this image as a shader with the specified tiling. It will use cubic sampling.\n * @param tx - tile mode in the x direction.\n * @param ty - tile mode in the y direction.\n * @param fm - The filter mode. (default nearest)\n * @param mm - The mipmap mode. Note: for settings other than None, the image must have mipmaps (default none)\n * calculated with makeCopyWithDefaultMipmaps;\n * @param localMatrix\n */\n makeShaderOptions(\n tx: TileMode,\n ty: TileMode,\n fm: FilterMode,\n mm: MipmapMode,\n localMatrix?: SkMatrix\n ): SkShader;\n\n /**\n * Returns this image as a shader with the specified tiling. It will use cubic sampling.\n * @param tx - tile mode in the x direction.\n * @param ty - tile mode in the y direction.\n * @param B - See CubicResampler in SkSamplingOptions.h for more information\n * @param C - See CubicResampler in SkSamplingOptions.h for more information\n * @param localMatrix\n */\n makeShaderCubic(\n tx: TileMode,\n ty: TileMode,\n B: number,\n C: number,\n localMatrix?: SkMatrix\n ): SkShader;\n\n /** Encodes Image pixels, returning result as UInt8Array. Returns existing\n encoded data if present; otherwise, SkImage is encoded with\n SkEncodedImageFormat::kPNG. Skia must be built with SK_ENCODE_PNG to encode\n SkImage.\n\n Returns nullptr if existing encoded data is missing or invalid, and\n encoding fails.\n\n @param fmt - PNG is the default value.\n @param quality - a value from 0 to 100; 100 is the least lossy. May be ignored.\n\n @return Uint8Array with data\n */\n encodeToBytes(fmt?: ImageFormat, quality?: number): Uint8Array;\n\n /** Encodes Image pixels, returning result as a base64 encoded string. Returns existing\n encoded data if present; otherwise, SkImage is encoded with\n SkEncodedImageFormat::kPNG. Skia must be built with SK_ENCODE_PNG to encode\n SkImage.\n\n Returns nullptr if existing encoded data is missing or invalid, and\n encoding fails.\n\n @param fmt - PNG is the default value.\n @param quality - a value from 0 to 100; 100 is the least lossy. May be ignored.\n\n @return base64 encoded string of data\n */\n encodeToBase64(fmt?: ImageFormat, quality?: number): string;\n\n /** Read Image pixels\n *\n * @param srcX - optional x-axis upper left corner of the rectangle to read from\n * @param srcY - optional y-axis upper left corner of the rectangle to read from\n * @param imageInfo - optional describes the pixel format and dimensions of the data to read into\n * @return Float32Array or Uint8Array with data or null if the read failed.\n */\n readPixels(\n srcX?: number,\n srcY?: number,\n imageInfo?: ImageInfo\n ): Float32Array | Uint8Array | null;\n\n /**\n * Returns raster image or lazy image. Copies SkImage backed by GPU texture\n * into CPU memory if needed. Returns original SkImage if decoded in raster\n * bitmap, or if encoded in a stream.\n */\n makeNonTextureImage(): SkImage;\n}\n"],"mappings":"AAiBA,WAAYA,UAAU,0BAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAA,OAAVA,UAAU;AAAA;AAKtB,WAAYC,UAAU,0BAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAA,OAAVA,UAAU;AAAA;AAMtB,WAAYC,WAAW,0BAAXA,WAAW;EAAXA,WAAW,CAAXA,WAAW;EAAXA,WAAW,CAAXA,WAAW;EAAXA,WAAW,CAAXA,WAAW;EAAA,OAAXA,WAAW;AAAA;AAQvB,OAAO,MAAMC,eAAe,GAC1BC,QAAyB,IACM;EAC/B,SAAS;;EACT,OAAO,GAAG,IAAIA,QAAQ,IAAI,GAAG,IAAIA,QAAQ;AAC3C,CAAC;AAED,OAAO,MAAMC,qBAAqB,GAAG;EAAEC,CAAC,EAAE,CAAC,GAAG,GAAG;EAAEC,CAAC,EAAE,CAAC,GAAG;AAAI,CAAC;AAC/D,OAAO,MAAMC,uBAAuB,GAAG;EAAEF,CAAC,EAAE,CAAC;EAAEC,CAAC,EAAE,CAAC,GAAG;AAAI,CAAC;AAC3D,OAAO,MAAME,aAAa,GAAG;EAAEH,CAAC,EAAE,CAAC;EAAEC,CAAC,EAAE;AAAE,CAAC;AAC3C,OAAO,MAAMG,SAAS,GAAGA,CAACJ,CAAS,EAAEC,CAAS,MAAM;EAAED,CAAC;EAAEC;AAAE,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["FilterMode","MipmapMode","ImageFormat","isCubicSampling","sampling","MitchellCubicSampling","B","C","CatmullRomCubicSampling","CubicSampling","MakeCubic"],"sources":["Image.ts"],"sourcesContent":["import type { SkMatrix } from \"../Matrix\";\nimport type { SkJSIInstance } from \"../JsiInstance\";\nimport type { TileMode } from \"../ImageFilter\";\nimport type { SkShader } from \"../Shader\";\n\nimport type { ImageInfo } from \"./ImageFactory\";\n\nexport interface CubicResampler {\n B: number;\n C: number;\n}\n\nexport interface FilterOptions {\n filter: FilterMode;\n mipmap?: MipmapMode;\n}\n\nexport enum FilterMode {\n Nearest,\n Linear,\n}\n\nexport enum MipmapMode {\n None,\n Nearest,\n Linear,\n}\n\nexport enum ImageFormat {\n JPEG = 3,\n PNG = 4,\n WEBP = 6,\n}\n\nexport type SamplingOptions = CubicResampler | FilterOptions;\n\nexport const isCubicSampling = (\n sampling: SamplingOptions\n): sampling is CubicResampler => {\n \"worklet\";\n return \"B\" in sampling && \"C\" in sampling;\n};\n\nexport const MitchellCubicSampling = { B: 1 / 3.0, C: 1 / 3.0 };\nexport const CatmullRomCubicSampling = { B: 0, C: 1 / 2.0 };\nexport const CubicSampling = { B: 0, C: 0 };\nexport const MakeCubic = (B: number, C: number) => ({ B, C });\n\nexport interface SkImage extends SkJSIInstance<\"Image\"> {\n /**\n * Returns the possibly scaled height of the image.\n */\n height(): number;\n\n /**\n * Returns the possibly scaled width of the image.\n */\n width(): number;\n\n /**\n * Returns the ImageInfo describing the image.\n */\n getImageInfo(): ImageInfo;\n\n /**\n * Returns the backend texture of the image.\n * The returned object can be used to create a Skia Image object.\n * The returned object is backend specific and should be used with caution.\n * It is the caller's responsibility to ensure that the texture is not used after the image is deleted.\n * The returned object may be null if the image does not have a backend texture.\n *\n * @return backend texture of the image or null\n */\n getNativeTextureUnstable(): unknown;\n\n /**\n * Returns this image as a shader with the specified tiling. It will use cubic sampling.\n * @param tx - tile mode in the x direction.\n * @param ty - tile mode in the y direction.\n * @param fm - The filter mode. (default nearest)\n * @param mm - The mipmap mode. Note: for settings other than None, the image must have mipmaps (default none)\n * calculated with makeCopyWithDefaultMipmaps;\n * @param localMatrix\n */\n makeShaderOptions(\n tx: TileMode,\n ty: TileMode,\n fm: FilterMode,\n mm: MipmapMode,\n localMatrix?: SkMatrix\n ): SkShader;\n\n /**\n * Returns this image as a shader with the specified tiling. It will use cubic sampling.\n * @param tx - tile mode in the x direction.\n * @param ty - tile mode in the y direction.\n * @param B - See CubicResampler in SkSamplingOptions.h for more information\n * @param C - See CubicResampler in SkSamplingOptions.h for more information\n * @param localMatrix\n */\n makeShaderCubic(\n tx: TileMode,\n ty: TileMode,\n B: number,\n C: number,\n localMatrix?: SkMatrix\n ): SkShader;\n\n /** Encodes Image pixels, returning result as UInt8Array. Returns existing\n encoded data if present; otherwise, SkImage is encoded with\n SkEncodedImageFormat::kPNG. Skia must be built with SK_ENCODE_PNG to encode\n SkImage.\n\n Returns nullptr if existing encoded data is missing or invalid, and\n encoding fails.\n\n @param fmt - PNG is the default value.\n @param quality - a value from 0 to 100; 100 is the least lossy. May be ignored.\n\n @return Uint8Array with data\n */\n encodeToBytes(fmt?: ImageFormat, quality?: number): Uint8Array;\n\n /** Encodes Image pixels, returning result as a base64 encoded string. Returns existing\n encoded data if present; otherwise, SkImage is encoded with\n SkEncodedImageFormat::kPNG. Skia must be built with SK_ENCODE_PNG to encode\n SkImage.\n\n Returns nullptr if existing encoded data is missing or invalid, and\n encoding fails.\n\n @param fmt - PNG is the default value.\n @param quality - a value from 0 to 100; 100 is the least lossy. May be ignored.\n\n @return base64 encoded string of data\n */\n encodeToBase64(fmt?: ImageFormat, quality?: number): string;\n\n /** Read Image pixels\n *\n * @param srcX - optional x-axis upper left corner of the rectangle to read from\n * @param srcY - optional y-axis upper left corner of the rectangle to read from\n * @param imageInfo - optional describes the pixel format and dimensions of the data to read into\n * @return Float32Array or Uint8Array with data or null if the read failed.\n */\n readPixels(\n srcX?: number,\n srcY?: number,\n imageInfo?: ImageInfo\n ): Float32Array | Uint8Array | null;\n\n /**\n * Returns raster image or lazy image. Copies SkImage backed by GPU texture\n * into CPU memory if needed. Returns original SkImage if decoded in raster\n * bitmap, or if encoded in a stream.\n * Returns null if the conversion fails.\n */\n makeNonTextureImage(): SkImage | null;\n}\n"],"mappings":"AAiBA,WAAYA,UAAU,0BAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAA,OAAVA,UAAU;AAAA;AAKtB,WAAYC,UAAU,0BAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAVA,UAAU,CAAVA,UAAU;EAAA,OAAVA,UAAU;AAAA;AAMtB,WAAYC,WAAW,0BAAXA,WAAW;EAAXA,WAAW,CAAXA,WAAW;EAAXA,WAAW,CAAXA,WAAW;EAAXA,WAAW,CAAXA,WAAW;EAAA,OAAXA,WAAW;AAAA;AAQvB,OAAO,MAAMC,eAAe,GAC1BC,QAAyB,IACM;EAC/B,SAAS;;EACT,OAAO,GAAG,IAAIA,QAAQ,IAAI,GAAG,IAAIA,QAAQ;AAC3C,CAAC;AAED,OAAO,MAAMC,qBAAqB,GAAG;EAAEC,CAAC,EAAE,CAAC,GAAG,GAAG;EAAEC,CAAC,EAAE,CAAC,GAAG;AAAI,CAAC;AAC/D,OAAO,MAAMC,uBAAuB,GAAG;EAAEF,CAAC,EAAE,CAAC;EAAEC,CAAC,EAAE,CAAC,GAAG;AAAI,CAAC;AAC3D,OAAO,MAAME,aAAa,GAAG;EAAEH,CAAC,EAAE,CAAC;EAAEC,CAAC,EAAE;AAAE,CAAC;AAC3C,OAAO,MAAMG,SAAS,GAAGA,CAACJ,CAAS,EAAEC,CAAS,MAAM;EAAED,CAAC;EAAEC;AAAE,CAAC,CAAC","ignoreList":[]}
@@ -35,18 +35,16 @@ class NativeReanimatedContainer extends Container {
35
35
  const recorder = new ReanimatedRecorder(this.Skia);
36
36
  const {
37
37
  nativeId,
38
- picture,
39
- Skia
38
+ picture
40
39
  } = this;
41
40
  visit(recorder, this.root);
42
41
  const sharedValues = recorder.getSharedValues();
43
42
  const sharedRecorder = recorder.getRecorder();
44
43
  // Draw first frame
45
- Rea.executeOnUIRuntimeSync(() => {
44
+ Rea.runOnUI(() => {
46
45
  "worklet";
47
46
 
48
- const firstPicture = Skia.Picture.MakePicture(null);
49
- nativeDrawOnscreen(nativeId, sharedRecorder, firstPicture);
47
+ nativeDrawOnscreen(nativeId, sharedRecorder, picture);
50
48
  })();
51
49
  // Animate
52
50
  if (sharedValues.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"names":["Rea","HAS_REANIMATED_3","ReanimatedRecorder","Container","StaticContainer","visit","nativeDrawOnscreen","nativeId","recorder","picture","play","SkiaViewApi","setJsiProperty","NativeReanimatedContainer","constructor","Skia","_defineProperty","Picture","MakePicture","redraw","mapperId","stopMapper","unmounted","root","sharedValues","getSharedValues","sharedRecorder","getRecorder","executeOnUIRuntimeSync","firstPicture","length","startMapper","applyUpdates","createContainer"],"sources":["Container.native.ts"],"sourcesContent":["import Rea from \"../external/reanimated/ReanimatedProxy\";\nimport type { Skia, SkPicture } from \"../skia/types\";\nimport { HAS_REANIMATED_3 } from \"../external/reanimated/renderHelpers\";\nimport type { JsiRecorder } from \"../skia/types/Recorder\";\n\nimport { ReanimatedRecorder } from \"./Recorder/ReanimatedRecorder\";\nimport { Container, StaticContainer } from \"./StaticContainer\";\nimport { visit } from \"./Recorder/Visitor\";\n\nimport \"../skia/NativeSetup\";\nimport \"../views/api\";\n\nconst nativeDrawOnscreen = (\n nativeId: number,\n recorder: JsiRecorder,\n picture: SkPicture\n) => {\n \"worklet\";\n\n //const start = performance.now();\n recorder.play(picture);\n //const end = performance.now();\n //console.log(\"Recording time: \", end - start);\n SkiaViewApi.setJsiProperty(nativeId, \"picture\", picture);\n};\n\nclass NativeReanimatedContainer extends Container {\n private mapperId: number | null = null;\n private picture: SkPicture;\n\n constructor(\n Skia: Skia,\n private nativeId: number\n ) {\n super(Skia);\n this.picture = Skia.Picture.MakePicture(null)!;\n }\n\n redraw() {\n if (this.mapperId !== null) {\n Rea.stopMapper(this.mapperId);\n }\n if (this.unmounted) {\n return;\n }\n const recorder = new ReanimatedRecorder(this.Skia);\n const { nativeId, picture, Skia } = this;\n visit(recorder, this.root);\n const sharedValues = recorder.getSharedValues();\n const sharedRecorder = recorder.getRecorder();\n // Draw first frame\n Rea.executeOnUIRuntimeSync(() => {\n \"worklet\";\n const firstPicture = Skia.Picture.MakePicture(null)!;\n nativeDrawOnscreen(nativeId, sharedRecorder, firstPicture);\n })();\n // Animate\n if (sharedValues.length > 0) {\n this.mapperId = Rea.startMapper(() => {\n \"worklet\";\n sharedRecorder.applyUpdates(sharedValues);\n nativeDrawOnscreen(nativeId, sharedRecorder, picture);\n }, sharedValues);\n }\n }\n}\n\nexport const createContainer = (Skia: Skia, nativeId: number) => {\n if (HAS_REANIMATED_3 && nativeId !== -1) {\n return new NativeReanimatedContainer(Skia, nativeId);\n } else {\n return new StaticContainer(Skia, nativeId);\n }\n};\n"],"mappings":";;;AAAA,OAAOA,GAAG,MAAM,wCAAwC;AAExD,SAASC,gBAAgB,QAAQ,sCAAsC;AAGvE,SAASC,kBAAkB,QAAQ,+BAA+B;AAClE,SAASC,SAAS,EAAEC,eAAe,QAAQ,mBAAmB;AAC9D,SAASC,KAAK,QAAQ,oBAAoB;AAE1C,OAAO,qBAAqB;AAC5B,OAAO,cAAc;AAErB,MAAMC,kBAAkB,GAAGA,CACzBC,QAAgB,EAChBC,QAAqB,EACrBC,OAAkB,KACf;EACH,SAAS;;EAET;EACAD,QAAQ,CAACE,IAAI,CAACD,OAAO,CAAC;EACtB;EACA;EACAE,WAAW,CAACC,cAAc,CAACL,QAAQ,EAAE,SAAS,EAAEE,OAAO,CAAC;AAC1D,CAAC;AAED,MAAMI,yBAAyB,SAASV,SAAS,CAAC;EAIhDW,WAAWA,CACTC,IAAU,EACFR,QAAgB,EACxB;IACA,KAAK,CAACQ,IAAI,CAAC;IAAC,KAFJR,QAAgB,GAAhBA,QAAgB;IAAAS,eAAA,mBALQ,IAAI;IAAAA,eAAA;IAQpC,IAAI,CAACP,OAAO,GAAGM,IAAI,CAACE,OAAO,CAACC,WAAW,CAAC,IAAI,CAAE;EAChD;EAEAC,MAAMA,CAAA,EAAG;IACP,IAAI,IAAI,CAACC,QAAQ,KAAK,IAAI,EAAE;MAC1BpB,GAAG,CAACqB,UAAU,CAAC,IAAI,CAACD,QAAQ,CAAC;IAC/B;IACA,IAAI,IAAI,CAACE,SAAS,EAAE;MAClB;IACF;IACA,MAAMd,QAAQ,GAAG,IAAIN,kBAAkB,CAAC,IAAI,CAACa,IAAI,CAAC;IAClD,MAAM;MAAER,QAAQ;MAAEE,OAAO;MAAEM;IAAK,CAAC,GAAG,IAAI;IACxCV,KAAK,CAACG,QAAQ,EAAE,IAAI,CAACe,IAAI,CAAC;IAC1B,MAAMC,YAAY,GAAGhB,QAAQ,CAACiB,eAAe,CAAC,CAAC;IAC/C,MAAMC,cAAc,GAAGlB,QAAQ,CAACmB,WAAW,CAAC,CAAC;IAC7C;IACA3B,GAAG,CAAC4B,sBAAsB,CAAC,MAAM;MAC/B,SAAS;;MACT,MAAMC,YAAY,GAAGd,IAAI,CAACE,OAAO,CAACC,WAAW,CAAC,IAAI,CAAE;MACpDZ,kBAAkB,CAACC,QAAQ,EAAEmB,cAAc,EAAEG,YAAY,CAAC;IAC5D,CAAC,CAAC,CAAC,CAAC;IACJ;IACA,IAAIL,YAAY,CAACM,MAAM,GAAG,CAAC,EAAE;MAC3B,IAAI,CAACV,QAAQ,GAAGpB,GAAG,CAAC+B,WAAW,CAAC,MAAM;QACpC,SAAS;;QACTL,cAAc,CAACM,YAAY,CAACR,YAAY,CAAC;QACzClB,kBAAkB,CAACC,QAAQ,EAAEmB,cAAc,EAAEjB,OAAO,CAAC;MACvD,CAAC,EAAEe,YAAY,CAAC;IAClB;EACF;AACF;AAEA,OAAO,MAAMS,eAAe,GAAGA,CAAClB,IAAU,EAAER,QAAgB,KAAK;EAC/D,IAAIN,gBAAgB,IAAIM,QAAQ,KAAK,CAAC,CAAC,EAAE;IACvC,OAAO,IAAIM,yBAAyB,CAACE,IAAI,EAAER,QAAQ,CAAC;EACtD,CAAC,MAAM;IACL,OAAO,IAAIH,eAAe,CAACW,IAAI,EAAER,QAAQ,CAAC;EAC5C;AACF,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["Rea","HAS_REANIMATED_3","ReanimatedRecorder","Container","StaticContainer","visit","nativeDrawOnscreen","nativeId","recorder","picture","play","SkiaViewApi","setJsiProperty","NativeReanimatedContainer","constructor","Skia","_defineProperty","Picture","MakePicture","redraw","mapperId","stopMapper","unmounted","root","sharedValues","getSharedValues","sharedRecorder","getRecorder","runOnUI","length","startMapper","applyUpdates","createContainer"],"sources":["Container.native.ts"],"sourcesContent":["import Rea from \"../external/reanimated/ReanimatedProxy\";\nimport type { Skia, SkPicture } from \"../skia/types\";\nimport { HAS_REANIMATED_3 } from \"../external/reanimated/renderHelpers\";\nimport type { JsiRecorder } from \"../skia/types/Recorder\";\n\nimport { ReanimatedRecorder } from \"./Recorder/ReanimatedRecorder\";\nimport { Container, StaticContainer } from \"./StaticContainer\";\nimport { visit } from \"./Recorder/Visitor\";\n\nimport \"../skia/NativeSetup\";\nimport \"../views/api\";\n\nconst nativeDrawOnscreen = (\n nativeId: number,\n recorder: JsiRecorder,\n picture: SkPicture\n) => {\n \"worklet\";\n\n //const start = performance.now();\n recorder.play(picture);\n //const end = performance.now();\n //console.log(\"Recording time: \", end - start);\n SkiaViewApi.setJsiProperty(nativeId, \"picture\", picture);\n};\n\nclass NativeReanimatedContainer extends Container {\n private mapperId: number | null = null;\n private picture: SkPicture;\n\n constructor(\n Skia: Skia,\n private nativeId: number\n ) {\n super(Skia);\n this.picture = Skia.Picture.MakePicture(null)!;\n }\n\n redraw() {\n if (this.mapperId !== null) {\n Rea.stopMapper(this.mapperId);\n }\n if (this.unmounted) {\n return;\n }\n const recorder = new ReanimatedRecorder(this.Skia);\n const { nativeId, picture } = this;\n visit(recorder, this.root);\n const sharedValues = recorder.getSharedValues();\n const sharedRecorder = recorder.getRecorder();\n // Draw first frame\n Rea.runOnUI(() => {\n \"worklet\";\n nativeDrawOnscreen(nativeId, sharedRecorder, picture);\n })();\n // Animate\n if (sharedValues.length > 0) {\n this.mapperId = Rea.startMapper(() => {\n \"worklet\";\n sharedRecorder.applyUpdates(sharedValues);\n nativeDrawOnscreen(nativeId, sharedRecorder, picture);\n }, sharedValues);\n }\n }\n}\n\nexport const createContainer = (Skia: Skia, nativeId: number) => {\n if (HAS_REANIMATED_3 && nativeId !== -1) {\n return new NativeReanimatedContainer(Skia, nativeId);\n } else {\n return new StaticContainer(Skia, nativeId);\n }\n};\n"],"mappings":";;;AAAA,OAAOA,GAAG,MAAM,wCAAwC;AAExD,SAASC,gBAAgB,QAAQ,sCAAsC;AAGvE,SAASC,kBAAkB,QAAQ,+BAA+B;AAClE,SAASC,SAAS,EAAEC,eAAe,QAAQ,mBAAmB;AAC9D,SAASC,KAAK,QAAQ,oBAAoB;AAE1C,OAAO,qBAAqB;AAC5B,OAAO,cAAc;AAErB,MAAMC,kBAAkB,GAAGA,CACzBC,QAAgB,EAChBC,QAAqB,EACrBC,OAAkB,KACf;EACH,SAAS;;EAET;EACAD,QAAQ,CAACE,IAAI,CAACD,OAAO,CAAC;EACtB;EACA;EACAE,WAAW,CAACC,cAAc,CAACL,QAAQ,EAAE,SAAS,EAAEE,OAAO,CAAC;AAC1D,CAAC;AAED,MAAMI,yBAAyB,SAASV,SAAS,CAAC;EAIhDW,WAAWA,CACTC,IAAU,EACFR,QAAgB,EACxB;IACA,KAAK,CAACQ,IAAI,CAAC;IAAC,KAFJR,QAAgB,GAAhBA,QAAgB;IAAAS,eAAA,mBALQ,IAAI;IAAAA,eAAA;IAQpC,IAAI,CAACP,OAAO,GAAGM,IAAI,CAACE,OAAO,CAACC,WAAW,CAAC,IAAI,CAAE;EAChD;EAEAC,MAAMA,CAAA,EAAG;IACP,IAAI,IAAI,CAACC,QAAQ,KAAK,IAAI,EAAE;MAC1BpB,GAAG,CAACqB,UAAU,CAAC,IAAI,CAACD,QAAQ,CAAC;IAC/B;IACA,IAAI,IAAI,CAACE,SAAS,EAAE;MAClB;IACF;IACA,MAAMd,QAAQ,GAAG,IAAIN,kBAAkB,CAAC,IAAI,CAACa,IAAI,CAAC;IAClD,MAAM;MAAER,QAAQ;MAAEE;IAAQ,CAAC,GAAG,IAAI;IAClCJ,KAAK,CAACG,QAAQ,EAAE,IAAI,CAACe,IAAI,CAAC;IAC1B,MAAMC,YAAY,GAAGhB,QAAQ,CAACiB,eAAe,CAAC,CAAC;IAC/C,MAAMC,cAAc,GAAGlB,QAAQ,CAACmB,WAAW,CAAC,CAAC;IAC7C;IACA3B,GAAG,CAAC4B,OAAO,CAAC,MAAM;MAChB,SAAS;;MACTtB,kBAAkB,CAACC,QAAQ,EAAEmB,cAAc,EAAEjB,OAAO,CAAC;IACvD,CAAC,CAAC,CAAC,CAAC;IACJ;IACA,IAAIe,YAAY,CAACK,MAAM,GAAG,CAAC,EAAE;MAC3B,IAAI,CAACT,QAAQ,GAAGpB,GAAG,CAAC8B,WAAW,CAAC,MAAM;QACpC,SAAS;;QACTJ,cAAc,CAACK,YAAY,CAACP,YAAY,CAAC;QACzClB,kBAAkB,CAACC,QAAQ,EAAEmB,cAAc,EAAEjB,OAAO,CAAC;MACvD,CAAC,EAAEe,YAAY,CAAC;IAClB;EACF;AACF;AAEA,OAAO,MAAMQ,eAAe,GAAGA,CAACjB,IAAU,EAAER,QAAgB,KAAK;EAC/D,IAAIN,gBAAgB,IAAIM,QAAQ,KAAK,CAAC,CAAC,EAAE;IACvC,OAAO,IAAIM,yBAAyB,CAACE,IAAI,EAAER,QAAQ,CAAC;EACtD,CAAC,MAAM;IACL,OAAO,IAAIH,eAAe,CAACW,IAAI,EAAER,QAAQ,CAAC;EAC5C;AACF,CAAC","ignoreList":[]}
@@ -1,5 +1,5 @@
1
1
  export const __esModule: boolean;
2
2
  export function isOnMainThread(): boolean;
3
3
  export function drawAsPicture(element: any, bounds: any): Promise<import("../../..").SkPicture>;
4
- export function drawAsImage(element: any, size: any): Promise<import("../../..").SkImage>;
5
- export function drawAsImageFromPicture(picture: any, size: any): import("../../..").SkImage;
4
+ export function drawAsImage(element: any, size: any): Promise<import("../../..").SkImage | null>;
5
+ export function drawAsImageFromPicture(picture: any, size: any): import("../../..").SkImage | null;
@@ -1,4 +1,4 @@
1
1
  export function isOnMainThread(): boolean;
2
2
  export function drawAsPicture(element: any, bounds: any): Promise<import("../../..").SkPicture>;
3
- export function drawAsImage(element: any, size: any): Promise<import("../../..").SkImage>;
4
- export function drawAsImageFromPicture(picture: any, size: any): import("../../..").SkImage;
3
+ export function drawAsImage(element: any, size: any): Promise<import("../../..").SkImage | null>;
4
+ export function drawAsImageFromPicture(picture: any, size: any): import("../../..").SkImage | null;
@@ -19,6 +19,8 @@ export declare const useCanvasSize: (userRef?: RefObject<CanvasRef | null>) => {
19
19
  export declare const isFabric: boolean;
20
20
  export interface CanvasProps extends Omit<ViewProps, "onLayout"> {
21
21
  debug?: boolean;
22
+ /** @deprecated Not supported on Fabric. Use `onSize` or `useCanvasSize()` instead. */
23
+ onLayout?: ViewProps["onLayout"];
22
24
  opaque?: boolean;
23
25
  onSize?: SharedValue<SkSize>;
24
26
  colorSpace?: "p3" | "srgb";
@@ -1,6 +1,6 @@
1
1
  import type { ReactElement } from "react";
2
- import type { SkPicture, SkRect, SkSize } from "../skia/types";
2
+ import type { SkImage, SkPicture, SkRect, SkSize } from "../skia/types";
3
3
  export declare const isOnMainThread: () => boolean;
4
4
  export declare const drawAsPicture: (element: ReactElement, bounds?: SkRect) => Promise<SkPicture>;
5
- export declare const drawAsImage: (element: ReactElement, size: SkSize) => Promise<import("../skia").SkImage>;
6
- export declare const drawAsImageFromPicture: (picture: SkPicture, size: SkSize) => import("../skia").SkImage;
5
+ export declare const drawAsImage: (element: ReactElement, size: SkSize) => Promise<SkImage | null>;
6
+ export declare const drawAsImageFromPicture: (picture: SkPicture, size: SkSize) => SkImage | null;
@@ -125,6 +125,7 @@ export interface SkImage extends SkJSIInstance<"Image"> {
125
125
  * Returns raster image or lazy image. Copies SkImage backed by GPU texture
126
126
  * into CPU memory if needed. Returns original SkImage if decoded in raster
127
127
  * bitmap, or if encoded in a stream.
128
+ * Returns null if the conversion fails.
128
129
  */
129
- makeNonTextureImage(): SkImage;
130
+ makeNonTextureImage(): SkImage | null;
130
131
  }
package/package.json CHANGED
@@ -8,37 +8,13 @@
8
8
  "setup-skia-web": "scripts/setup-canvaskit.js"
9
9
  },
10
10
  "title": "React Native Skia",
11
- "version": "2.4.20",
12
- "skia": {
13
- "version": "m144c",
14
- "checksums": {
15
- "android-armeabi-v7a": "e406c3e8103a2efb6a514ac91346d7f9f81adbae14dc2d0e302e84fb8c5f80f7",
16
- "android-arm64-v8a": "75069b0f7c66ad3382553e947d583265de033cc856c394110243da098306955f",
17
- "android-x86": "714b93a7bdf005a23699f47e6255e4e690086c52a1998c20196a46f95b709b09",
18
- "android-x86_64": "5bd2972d13293b09b35e2c0149b7d103dc4fb0f2837c3dd169ce06795b812714",
19
- "apple-ios-xcframeworks": "43f62ea742c55ecc57864505ff752a517fd2c31412a19914032d044ac4f987ee",
20
- "apple-tvos-xcframeworks": "0f6b5c75b4e686e72f5cc8508e60074463f757ca7a0dcbd07e095c055a537c58",
21
- "apple-macos-xcframeworks": "31f57bcf6caff1c268984609b0e4a2abd966bfa8ddcf074331d94e0f988f93d3"
22
- }
23
- },
24
- "skia-graphite": {
25
- "version": "m142b",
26
- "checksums": {
27
- "android-armeabi-v7a": "3e40f44c804194fa0983c46903f834e8f834c6dd96534c7fa1b4ebb4f409527d",
28
- "android-arm64-v8a": "d6c3035449fcf7ef13369b0d6c4ef41f3177d15074eeb195201e0ba4cfb2f527",
29
- "android-x86": "6dc229847420b8a43c15098cdcb4fe45b2df20a38ad69f37e0aa91c832499c2a",
30
- "android-x86_64": "ecae351d98af3b175d40d894520c2e3263034276bb0b0e9d2f9c19ba7dc046fa",
31
- "apple-ios-xcframeworks": "6f60f03faaeebfb798615d09715040790ff95e75bf95028893ced6f514ab5196",
32
- "apple-macos-xcframeworks": "07467cd1778053537528ed91c7a35d116e1a4644819f0aad8e06e7d884591dea"
33
- }
34
- },
11
+ "version": "2.5.0",
35
12
  "description": "High-performance React Native Graphics using Skia",
36
13
  "main": "lib/module/index.js",
37
14
  "react-native": "src/index.ts",
38
15
  "module": "lib/module/index.js",
39
16
  "types": "lib/typescript/index.d.ts",
40
17
  "files": [
41
- "scripts/install-skia.mjs",
42
18
  "scripts/setup-canvaskit.js",
43
19
  "src/**",
44
20
  "lib/**",
@@ -68,14 +44,13 @@
68
44
  "clean-skia": "yarn rimraf ./libs && yarn rimraf ../../externals/skia/out",
69
45
  "build-skia": "tsx ./scripts/build-skia.ts",
70
46
  "copy-skia-headers": "tsx ./scripts/copy-skia-headers.ts",
71
- "install-skia": "node ./scripts/install-skia.mjs --force && yarn copy-skia-headers",
47
+ "install-skia-graphite": "tsx ./scripts/install-skia-graphite.ts",
72
48
  "clang-format": "yarn clang-format-ios && yarn clang-format-android && yarn clang-format-common",
73
49
  "clang-format-ios": "find apple/ -iname '*.h' -o -iname '*.mm' -o -iname '*.cpp' | xargs clang-format -i",
74
50
  "clang-format-android": "find android/cpp/ -iname '*.h' -o -iname '*.m' -o -iname '*.cpp' | xargs clang-format -i",
75
51
  "clang-format-common": "find cpp/ \\( -path 'cpp//skia' -prune \\) -o \\( -iname '*.h' -o -iname '*.m' -o -iname '*.cpp' \\) -print | xargs clang-format -i",
76
52
  "workflow-copy-libs": "tsx ./scripts/workflow-copy-libs.ts",
77
- "cpplint": "cpplint --linelength=230 --filter=-legal/copyright,-whitespace/indent,-whitespace/comments,-whitespace/ending_newline,-build/include_order,-runtime/references,-readability/todo,-whitespace/blank_line,-whitespace/todo,-runtime/int,-build/c++11,-whitespace/parens --exclude=package/cpp/skia --exclude=package/ios --exclude=package/android/build --exclude=package/node_modules --recursive package",
78
- "postinstall": "node ./scripts/install-skia.mjs"
53
+ "cpplint": "cpplint --linelength=230 --filter=-legal/copyright,-whitespace/indent,-whitespace/comments,-whitespace/ending_newline,-build/include_order,-runtime/references,-readability/todo,-whitespace/blank_line,-whitespace/todo,-runtime/int,-build/c++11,-whitespace/parens --exclude=package/cpp/skia --exclude=package/ios --exclude=package/android/build --exclude=package/node_modules --recursive package"
79
54
  },
80
55
  "repository": {
81
56
  "type": "git",
@@ -137,11 +112,12 @@
137
112
  "react": "19.0.0",
138
113
  "react-native": "0.83.1",
139
114
  "react-native-builder-bob": "0.18.2",
140
- "react-native-reanimated": "4.2.1",
141
- "react-native-worklets": "0.7.1",
115
+ "react-native-reanimated": "^4.2.1",
116
+ "react-native-worklets": "^0.7.0",
142
117
  "rimraf": "3.0.2",
143
118
  "semantic-release": "^24.1.0",
144
119
  "semantic-release-yarn": "^3.0.2",
120
+ "tar": "^7.5.9",
145
121
  "ts-jest": "29.4.3",
146
122
  "tsx": "^4.21.0",
147
123
  "typescript": "^5.2.2",
@@ -149,6 +125,10 @@
149
125
  },
150
126
  "dependencies": {
151
127
  "canvaskit-wasm": "0.40.0",
128
+ "react-native-skia-android": "144.3.0",
129
+ "react-native-skia-apple-ios": "144.3.0",
130
+ "react-native-skia-apple-macos": "144.3.0",
131
+ "react-native-skia-apple-tvos": "144.3.0",
152
132
  "react-reconciler": "0.31.0"
153
133
  },
154
134
  "eslintIgnore": [
@@ -4,76 +4,122 @@ require "json"
4
4
 
5
5
  package = JSON.parse(File.read(File.join(__dir__, "package.json")))
6
6
 
7
- # Check if Skia prebuilt binaries are installed
8
- # The postinstall script downloads these - if missing, the user needs to run it
9
- skia_libs_path = File.join(__dir__, "libs/apple/ios")
10
- unless File.exist?(skia_libs_path) && Dir.glob(File.join(skia_libs_path, "*.xcframework")).any?
11
- Pod::UI.puts "\n"
12
- Pod::UI.puts "┌─────────────────────────────────────────────────────────────────────────────┐".red
13
- Pod::UI.puts "│ │".red
14
- Pod::UI.puts "│ ERROR: Skia prebuilt binaries not found! │".red
15
- Pod::UI.puts "│ │".red
16
- Pod::UI.puts "│ The postinstall script has not run. This is required to download the │".red
17
- Pod::UI.puts "│ Skia binaries. Some package managers (pnpm, bun, yarn berry) require │".red
18
- Pod::UI.puts "│ explicit trust for packages with postinstall scripts. │".red
19
- Pod::UI.puts "│ │".red
20
- Pod::UI.puts "│ To fix this: │".red
21
- Pod::UI.puts "│ │".red
22
- Pod::UI.puts "│ • npm/yarn classic: Run 'npm rebuild @shopify/react-native-skia' or │".red
23
- Pod::UI.puts "│ reinstall the package │".red
24
- Pod::UI.puts "│ │".red
25
- Pod::UI.puts "│ • bun: Run 'bun add --trust @shopify/react-native-skia' │".red
26
- Pod::UI.puts "│ │".red
27
- Pod::UI.puts "│ • pnpm: Add to package.json: │".red
28
- Pod::UI.puts "│ \"pnpm\": { \"onlyBuiltDependencies\": [\"@shopify/react-native-skia\"] }│".red
29
- Pod::UI.puts "│ Then reinstall the package │".red
30
- Pod::UI.puts "│ │".red
31
- Pod::UI.puts "│ See: https://shopify.github.io/react-native-skia/docs/getting-started/installation │".red
32
- Pod::UI.puts "│ │".red
33
- Pod::UI.puts "└─────────────────────────────────────────────────────────────────────────────┘".red
34
- Pod::UI.puts "\n"
35
- raise "Skia prebuilt binaries not found. Please run the postinstall script."
7
+ # Resolve npm package path using Node.js resolution (handles monorepos, pnpm, etc.)
8
+ resolve_skia_package = lambda do |package_name, required: true|
9
+ begin
10
+ # Use node to resolve the package - this handles all edge cases:
11
+ # - Hoisted packages in monorepos
12
+ # - pnpm symlinked packages
13
+ # - Yarn PnP
14
+ # - Different node_modules structures
15
+ result = `node -e "console.log(require.resolve('#{package_name}/package.json'))" 2>/dev/null`.strip
16
+ if $?.success? && !result.empty?
17
+ return File.dirname(result)
18
+ end
19
+ rescue => e
20
+ # Node resolution failed
21
+ end
22
+
23
+ # Fallback: walk up directories looking for node_modules
24
+ current = __dir__
25
+ while current != "/"
26
+ candidate = File.join(current, "node_modules", package_name)
27
+ if File.exist?(File.join(candidate, "package.json"))
28
+ return candidate
29
+ end
30
+ current = File.dirname(current)
31
+ end
32
+
33
+ if required
34
+ Pod::UI.puts "\n"
35
+ Pod::UI.puts "ERROR: Could not find #{package_name}".red
36
+ Pod::UI.puts "Make sure you have run 'yarn install' or 'npm install'".red
37
+ Pod::UI.puts "\n"
38
+ raise "#{package_name} not found. Please install dependencies."
39
+ end
40
+
41
+ nil
36
42
  end
37
43
 
38
- # Check if Graphite is available
39
- # Detection method priority:
40
- # 1. SK_GRAPHITE environment variable (explicit override, fastest)
41
- # 2. Marker file in libs directory (set during Skia build)
42
- # 3. Default to OFF (no slow nm symbol detection)
44
+ # Check if Graphite is enabled
43
45
  use_graphite = false
44
-
45
46
  if ENV['SK_GRAPHITE']
46
- # Explicit override via environment variable
47
47
  use_graphite = ENV['SK_GRAPHITE'] == '1' || ENV['SK_GRAPHITE'].downcase == 'true'
48
- puts "-- SK_GRAPHITE detection: using environment variable (#{use_graphite ? 'ON' : 'OFF'})"
49
- elsif File.exist?(File.join(__dir__, "libs/apple/graphite.enabled"))
50
- # Marker file indicates Graphite-enabled build
51
- use_graphite = true
52
- puts "-- SK_GRAPHITE detection: marker file found"
48
+ puts "-- SK_GRAPHITE: using environment variable (#{use_graphite ? 'ON' : 'OFF'})"
53
49
  else
54
- puts "-- SK_GRAPHITE detection: no marker file, assuming OFF"
50
+ puts "-- SK_GRAPHITE: OFF (set SK_GRAPHITE=1 to enable)"
55
51
  end
56
52
 
57
- if use_graphite
58
- puts "-- SK_GRAPHITE: ON"
53
+ # Check if xcframeworks already exist (e.g., from install-skia-graphite script)
54
+ local_ios_libs = File.join(__dir__, "libs/ios")
55
+ local_macos_libs = File.join(__dir__, "libs/macos")
56
+ xcframeworks_preinstalled = File.exist?(local_ios_libs) &&
57
+ Dir.glob(File.join(local_ios_libs, "*.xcframework")).any? &&
58
+ File.exist?(local_macos_libs) &&
59
+ Dir.glob(File.join(local_macos_libs, "*.xcframework")).any?
60
+
61
+ if xcframeworks_preinstalled
62
+ puts "-- Using pre-installed xcframeworks from libs/"
63
+ ios_package = nil
64
+ macos_package = nil
65
+ tvos_package = nil
59
66
  else
60
- puts "-- SK_GRAPHITE: OFF"
67
+ # Resolve Skia binary packages from npm
68
+ prefix = use_graphite ? "react-native-skia-graphite" : "react-native-skia"
69
+
70
+ ios_package = resolve_skia_package.call("#{prefix}-apple-ios")
71
+ macos_package = resolve_skia_package.call("#{prefix}-apple-macos")
72
+ tvos_package = use_graphite ? nil : resolve_skia_package.call("#{prefix}-apple-tvos", required: false)
73
+
74
+ puts "-- Skia iOS package: #{ios_package}"
75
+ puts "-- Skia macOS package: #{macos_package}"
76
+ puts "-- Skia tvOS package: #{tvos_package}" if tvos_package
77
+
78
+ # Verify the packages contain the expected files
79
+ ios_libs_path = File.join(ios_package, "libs")
80
+ unless File.exist?(ios_libs_path) && Dir.glob(File.join(ios_libs_path, "*.xcframework")).any?
81
+ Pod::UI.puts "\n"
82
+ Pod::UI.puts "┌─────────────────────────────────────────────────────────────────────────────┐".red
83
+ Pod::UI.puts "│ │".red
84
+ Pod::UI.puts "│ ERROR: Skia prebuilt binaries not found in #{prefix}-apple-ios! │".red
85
+ Pod::UI.puts "│ │".red
86
+ Pod::UI.puts "│ The package was found but doesn't contain the expected xcframeworks. │".red
87
+ Pod::UI.puts "│ Try reinstalling: yarn add #{prefix}-apple-ios │".red
88
+ Pod::UI.puts "│ │".red
89
+ Pod::UI.puts "└─────────────────────────────────────────────────────────────────────────────┘".red
90
+ Pod::UI.puts "\n"
91
+ raise "Skia xcframeworks not found in #{ios_libs_path}"
92
+ end
61
93
  end
62
94
 
63
95
  # Set preprocessor definitions based on GRAPHITE flag
64
- preprocessor_defs = use_graphite ?
65
- '$(inherited) SK_GRAPHITE=1 SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API=1 SK_DISABLE_LEGACY_SHAPER_FACTORY=1' :
96
+ preprocessor_defs = use_graphite ?
97
+ '$(inherited) SK_GRAPHITE=1 SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API=1 SK_DISABLE_LEGACY_SHAPER_FACTORY=1' :
66
98
  '$(inherited) SK_METAL=1 SK_GANESH=1 SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API=1 SK_DISABLE_LEGACY_SHAPER_FACTORY=1'
67
99
 
68
- # Define framework names (without paths)
100
+ # Define framework names
69
101
  framework_names = ['libskia', 'libsvg', 'libskshaper', 'libskparagraph',
70
102
  'libskunicode_core', 'libskunicode_libgrapheme',
71
103
  'libskottie', 'libsksg']
72
104
 
73
- # Build platform-specific framework paths
74
- ios_frameworks = framework_names.map { |f| "libs/apple/ios/#{f}.xcframework" }
75
- tvos_frameworks = framework_names.map { |f| "libs/apple/tvos/#{f}.xcframework" }
76
- osx_frameworks = framework_names.map { |f| "libs/apple/macos/#{f}.xcframework" }
105
+ # Build platform-specific framework paths (relative to pod's libs directory)
106
+ ios_frameworks = framework_names.map { |f| "libs/ios/#{f}.xcframework" }
107
+ osx_frameworks = framework_names.map { |f| "libs/macos/#{f}.xcframework" }
108
+ tvos_frameworks = tvos_package ? framework_names.map { |f| "libs/tvos/#{f}.xcframework" } : []
109
+
110
+ # Prepare command to copy xcframeworks from npm packages into pod directory
111
+ # (skipped if xcframeworks are already preinstalled)
112
+ prepare_commands = []
113
+ unless xcframeworks_preinstalled
114
+ prepare_commands << "rm -rf libs/ios libs/macos libs/tvos"
115
+ prepare_commands << "mkdir -p libs/ios libs/macos"
116
+ prepare_commands << "cp -R '#{ios_package}/libs/'*.xcframework libs/ios/"
117
+ prepare_commands << "cp -R '#{macos_package}/libs/'*.xcframework libs/macos/"
118
+ if tvos_package
119
+ prepare_commands << "mkdir -p libs/tvos"
120
+ prepare_commands << "cp -R '#{tvos_package}/libs/'*.xcframework libs/tvos/"
121
+ end
122
+ end
77
123
 
78
124
  Pod::Spec.new do |s|
79
125
  s.name = "react-native-skia"
@@ -85,13 +131,16 @@ Pod::Spec.new do |s|
85
131
  s.homepage = "https://github.com/shopify/react-native-skia"
86
132
  s.license = "MIT"
87
133
  s.license = { :type => "MIT", :file => "LICENSE.md" }
88
- s.authors = {
134
+ s.authors = {
89
135
  "Christian Falch" => "christian.falch@gmail.com",
90
136
  "William Candillon" => "wcandillon@gmail.com"
91
137
  }
92
138
  s.platforms = { :ios => "14.0", :tvos => "13.0", :osx => "11" }
93
139
  s.source = { :git => "https://github.com/shopify/react-native-skia/react-native-skia.git", :tag => "#{s.version}" }
94
140
 
141
+ # Copy xcframeworks from npm packages into pod directory structure
142
+ s.prepare_command = prepare_commands.join(" && ")
143
+
95
144
  s.requires_arc = true
96
145
  s.pod_target_xcconfig = {
97
146
  'GCC_PREPROCESSOR_DEFINITIONS' => preprocessor_defs,
@@ -102,7 +151,7 @@ Pod::Spec.new do |s|
102
151
 
103
152
  s.frameworks = ['MetalKit', 'AVFoundation', 'AVKit', 'CoreMedia']
104
153
 
105
- # Platform-specific vendored frameworks
154
+ # Platform-specific vendored frameworks (copied into libs/)
106
155
  s.ios.vendored_frameworks = ios_frameworks
107
156
  s.osx.vendored_frameworks = osx_frameworks
108
157
 
@@ -111,9 +160,12 @@ Pod::Spec.new do |s|
111
160
  s.tvos.vendored_frameworks = tvos_frameworks
112
161
  end
113
162
 
163
+ # Preserve the copied libs directory
164
+ s.preserve_paths = ["libs/**/*"]
165
+
114
166
  # All iOS cpp/h files
115
167
  s.source_files = [
116
- "apple/**/*.{h,c,cc,cpp,m,mm,swift}",
168
+ "apple/**/*.{h,c,cc,cpp,m,mm,swift}",
117
169
  "cpp/**/*.{h,cpp}"
118
170
  ]
119
171
 
@@ -123,9 +175,10 @@ Pod::Spec.new do |s|
123
175
  'cpp/rnskia/RNDawnWindowContext.h',
124
176
  'cpp/rnskia/RNDawnWindowContext.cpp',
125
177
  'cpp/rnskia/RNImageProvider.h',
126
- 'cpp/rnwgpu/**/*.{h,cpp}'
178
+ 'cpp/rnwgpu/**/*.{h,cpp}',
179
+ 'cpp/jsi2/**/*.{h,cpp}'
127
180
  ]
128
- s.exclude_files = graphite_exclusions unless use_graphite
181
+ s.exclude_files = graphite_exclusions unless use_graphite
129
182
 
130
183
  if defined?(install_modules_dependencies()) != nil
131
184
  install_modules_dependencies(s)
@@ -138,4 +191,3 @@ Pod::Spec.new do |s|
138
191
  s.dependency "React-Core"
139
192
  end
140
193
  end
141
-
@@ -64,6 +64,8 @@ export const isFabric = Boolean((global as any)?.nativeFabricUIManager);
64
64
 
65
65
  export interface CanvasProps extends Omit<ViewProps, "onLayout"> {
66
66
  debug?: boolean;
67
+ /** @deprecated Not supported on Fabric. Use `onSize` or `useCanvasSize()` instead. */
68
+ onLayout?: ViewProps["onLayout"];
67
69
  opaque?: boolean;
68
70
  onSize?: SharedValue<SkSize>;
69
71
  colorSpace?: "p3" | "srgb";
@@ -80,9 +82,6 @@ export const Canvas = ({
80
82
  colorSpace = "p3",
81
83
  androidWarmup = false,
82
84
  ref,
83
- // Here know this is a type error but this is done on purpose to check it at runtime
84
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
85
- // @ts-expect-error
86
85
  onLayout,
87
86
  ...viewProps
88
87
  }: CanvasProps) => {
@@ -1,6 +1,6 @@
1
1
  import type { ReactElement } from "react";
2
2
 
3
- import type { SkPicture, SkRect, SkSize } from "../skia/types";
3
+ import type { SkImage, SkPicture, SkRect, SkSize } from "../skia/types";
4
4
  import { Skia } from "../skia";
5
5
  import { Platform } from "../Platform";
6
6
  import { SkiaSGRoot } from "../sksg/Reconciler";
@@ -25,11 +25,17 @@ export const drawAsPicture = async (element: ReactElement, bounds?: SkRect) => {
25
25
  return picture;
26
26
  };
27
27
 
28
- export const drawAsImage = async (element: ReactElement, size: SkSize) => {
28
+ export const drawAsImage = async (
29
+ element: ReactElement,
30
+ size: SkSize
31
+ ): Promise<SkImage | null> => {
29
32
  return drawAsImageFromPicture(await drawAsPicture(element), size);
30
33
  };
31
34
 
32
- export const drawAsImageFromPicture = (picture: SkPicture, size: SkSize) => {
35
+ export const drawAsImageFromPicture = (
36
+ picture: SkPicture,
37
+ size: SkSize
38
+ ): SkImage | null => {
33
39
  "worklet";
34
40
  const surface = Skia.Surface.MakeOffscreen(size.width, size.height)!;
35
41
  const canvas = surface.getCanvas();
@@ -153,6 +153,7 @@ export interface SkImage extends SkJSIInstance<"Image"> {
153
153
  * Returns raster image or lazy image. Copies SkImage backed by GPU texture
154
154
  * into CPU memory if needed. Returns original SkImage if decoded in raster
155
155
  * bitmap, or if encoded in a stream.
156
+ * Returns null if the conversion fails.
156
157
  */
157
- makeNonTextureImage(): SkImage;
158
+ makeNonTextureImage(): SkImage | null;
158
159
  }
@@ -44,15 +44,14 @@ class NativeReanimatedContainer extends Container {
44
44
  return;
45
45
  }
46
46
  const recorder = new ReanimatedRecorder(this.Skia);
47
- const { nativeId, picture, Skia } = this;
47
+ const { nativeId, picture } = this;
48
48
  visit(recorder, this.root);
49
49
  const sharedValues = recorder.getSharedValues();
50
50
  const sharedRecorder = recorder.getRecorder();
51
51
  // Draw first frame
52
- Rea.executeOnUIRuntimeSync(() => {
52
+ Rea.runOnUI(() => {
53
53
  "worklet";
54
- const firstPicture = Skia.Picture.MakePicture(null)!;
55
- nativeDrawOnscreen(nativeId, sharedRecorder, firstPicture);
54
+ nativeDrawOnscreen(nativeId, sharedRecorder, picture);
56
55
  })();
57
56
  // Animate
58
57
  if (sharedValues.length > 0) {