react-native-nitro-image-pipeline 1.0.0 → 1.2.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 (37) hide show
  1. package/README.md +21 -6
  2. package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/HybridNitroImagePipeline.kt +34 -2
  3. package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/transform/ResizeTransformation.kt +59 -0
  4. package/ios/HybridNitroImagePipeline.swift +23 -2
  5. package/ios/RoundedCornersProcessor.swift +121 -0
  6. package/lib/commonjs/index.js +25 -2
  7. package/lib/commonjs/index.js.map +1 -1
  8. package/lib/module/index.js +25 -2
  9. package/lib/module/index.js.map +1 -1
  10. package/lib/typescript/src/index.d.ts +18 -6
  11. package/lib/typescript/src/index.d.ts.map +1 -1
  12. package/lib/typescript/src/specs/nitro-image-toolkit.nitro.d.ts +46 -1
  13. package/lib/typescript/src/specs/nitro-image-toolkit.nitro.d.ts.map +1 -1
  14. package/nitrogen/generated/android/NitroImagePipeline+autolinking.cmake +1 -0
  15. package/nitrogen/generated/android/c++/JCornerRadii.hpp +69 -0
  16. package/nitrogen/generated/android/c++/JHybridNitroImagePipelineSpec.cpp +10 -0
  17. package/nitrogen/generated/android/c++/JOptions.hpp +15 -5
  18. package/nitrogen/generated/android/c++/JResizeOptions.hpp +61 -0
  19. package/nitrogen/generated/android/c++/JVariant_Double_CornerRadii.cpp +26 -0
  20. package/nitrogen/generated/android/c++/JVariant_Double_CornerRadii.hpp +70 -0
  21. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroimagepipeline/CornerRadii.kt +66 -0
  22. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroimagepipeline/Options.kt +9 -4
  23. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroimagepipeline/ResizeOptions.kt +56 -0
  24. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroimagepipeline/Variant_Double_CornerRadii.kt +62 -0
  25. package/nitrogen/generated/ios/NitroImagePipeline-Swift-Cxx-Bridge.hpp +66 -0
  26. package/nitrogen/generated/ios/NitroImagePipeline-Swift-Cxx-Umbrella.hpp +7 -0
  27. package/nitrogen/generated/ios/c++/HybridNitroImagePipelineSpecSwift.hpp +7 -0
  28. package/nitrogen/generated/ios/swift/CornerRadii.swift +96 -0
  29. package/nitrogen/generated/ios/swift/Options.swift +38 -8
  30. package/nitrogen/generated/ios/swift/ResizeOptions.swift +34 -0
  31. package/nitrogen/generated/ios/swift/Variant_Double_CornerRadii.swift +30 -0
  32. package/nitrogen/generated/shared/c++/CornerRadii.hpp +95 -0
  33. package/nitrogen/generated/shared/c++/Options.hpp +16 -5
  34. package/nitrogen/generated/shared/c++/ResizeOptions.hpp +87 -0
  35. package/package.json +1 -1
  36. package/src/index.ts +52 -6
  37. package/src/specs/nitro-image-toolkit.nitro.ts +49 -1
package/README.md CHANGED
@@ -10,7 +10,7 @@ A high-performance image loading, caching, and processing library for React Nati
10
10
 
11
11
  - Load remote images with built-in memory and disk caching
12
12
  - Prefetch single or multiple images in the background
13
- - Apply Gaussian blur and rounded corners at load time
13
+ - Resize (aspect-fill, center-crop) and apply Gaussian blur and rounded corners (uniform or per-corner) at load time
14
14
  - Apply Gaussian blur to already-loaded images
15
15
  - Clear the image cache on demand
16
16
  - `useImage` hook for declarative image loading in components
@@ -46,10 +46,14 @@ The simplest way to load an image in a component:
46
46
  import { useImage } from 'react-native-nitro-image-pipeline';
47
47
 
48
48
  function MyComponent() {
49
+ const px = PixelRatio.get();
49
50
  const { image, error } = useImage({
50
51
  url: 'https://example.com/photo.jpg',
51
- blur: 4, // Gaussian sigma in source pixels — same result on iOS and Android
52
- cornerRadius: 12,
52
+ blur: 4, // Gaussian sigma in bitmap pixels — same result on iOS and Android
53
+ // Resize to the size you display (points × screen scale) so the corner
54
+ // radii apply 1:1 to what you see instead of the full-resolution source.
55
+ resize: { width: 300 * px, height: 200 * px },
56
+ cornerRadius: 12 * px,
53
57
  });
54
58
 
55
59
  if (error) return <Text>Failed to load image</Text>;
@@ -65,13 +69,23 @@ function MyComponent() {
65
69
  ```ts
66
70
  import { NitroImagePipeline } from 'react-native-nitro-image-pipeline';
67
71
 
68
- // Load an image with options
72
+ // Load an image with options. resize and cornerRadius are in pixels of the
73
+ // produced bitmap: without resize, the radius applies to the full-resolution
74
+ // source and shrinks along with it when displayed small.
69
75
  const image = await NitroImagePipeline.loadImage('https://example.com/photo.jpg', {
70
- blur: 4, // Gaussian sigma in source pixels — see "Blur units"
76
+ blur: 4, // Gaussian sigma in bitmap pixels — see "Blur units"
77
+ resize: { width: 600, height: 400 }, // aspect-fill + center-crop, exact output size
71
78
  cornerRadius: 12,
72
79
  cache: 'disk',
73
80
  });
74
81
 
82
+ // Per-corner radii — e.g. a "ticket" shape with larger bottom corners.
83
+ // The rounding is baked into the bitmap, so no view-layer masking is needed.
84
+ const ticket = await NitroImagePipeline.loadImage('https://example.com/photo.jpg', {
85
+ resize: { width: 600, height: 400 },
86
+ cornerRadius: { topLeft: 24, topRight: 24, bottomLeft: 48, bottomRight: 48 },
87
+ });
88
+
75
89
  // Prefetch a single image
76
90
  await NitroImagePipeline.preLoadImage('https://example.com/photo.jpg');
77
91
 
@@ -97,7 +111,8 @@ Loads an image from a URL and returns a `Promise<Image>`.
97
111
  | Option | Type | Default | Description |
98
112
  |---|---|---|---|
99
113
  | `blur` | `number` | `0` | Gaussian blur strength applied at load time — see [Blur units](#blur-units) |
100
- | `cornerRadius` | `number` | `0` | Corner radius in points |
114
+ | `resize` | `{ width, height }` | source size | Target bitmap size in pixels. Scales to fill and center-crops (CSS `object-fit: cover`, upscaling if needed) before `blur`/`cornerRadius` run, so their pixel units refer to this final size. Typically your display size in points × `PixelRatio.get()` |
115
+ | `cornerRadius` | `number \| CornerRadii` | `0` | Corner radius in pixels of the produced bitmap — a single number for all four corners, or `{ topLeft?, topRight?, bottomLeft?, bottomRight? }` for independent per-corner radii (omitted corners stay square). Pair with `resize` for radii that match your layout |
101
116
  | `cache` | `'memory' \| 'disk' \| 'none'` | platform default | Caching strategy |
102
117
 
103
118
  ### `preLoadImage(url)`
@@ -14,6 +14,7 @@ import coil3.request.ImageRequest
14
14
  import coil3.request.SuccessResult
15
15
  import coil3.request.allowHardware
16
16
  import coil3.request.transformations
17
+ import coil3.size.Scale
17
18
  import coil3.size.Size
18
19
  import coil3.transform.RoundedCornersTransformation
19
20
  import com.google.net.cronet.okhttptransport.CronetInterceptor
@@ -22,6 +23,8 @@ import com.margelo.nitro.core.Promise
22
23
  import com.margelo.nitro.image.HybridImage
23
24
  import com.margelo.nitro.image.HybridImageSpec
24
25
  import com.margelo.nitro.nitroimagepipeline.transform.BlurTransformation
26
+ import com.margelo.nitro.nitroimagepipeline.transform.ResizeTransformation
27
+ import kotlin.math.roundToInt
25
28
  import kotlinx.coroutines.Dispatchers
26
29
  import kotlinx.coroutines.async
27
30
  import kotlinx.coroutines.awaitAll
@@ -40,10 +43,32 @@ class HybridNitroImagePipeline : HybridNitroImagePipelineSpec() {
40
43
 
41
44
  override fun loadImage(url: String, options: Options?): Promise<HybridImageSpec> = Promise.async {
42
45
  val blur = options?.blur?.toFloat() ?: 0f
43
- val cornerRadius = options?.cornerRadius?.toFloat() ?: 0f
46
+ val resize =
47
+ options?.resize?.let { r ->
48
+ val width = r.width.roundToInt()
49
+ val height = r.height.roundToInt()
50
+ if (width > 0 && height > 0) width to height else null
51
+ }
44
52
  val transformations = buildList {
53
+ // Resize first: blur sigma and corner radii are in pixels of the bitmap
54
+ // they run on, so they must see the final size.
55
+ resize?.let { (width, height) -> add(ResizeTransformation(width, height)) }
45
56
  if (blur > 0f) add(BlurTransformation(context, blur))
46
- if (cornerRadius > 0f) add(RoundedCornersTransformation(cornerRadius))
57
+ options?.cornerRadius?.match(
58
+ first = { radius ->
59
+ if (radius > 0.0) add(RoundedCornersTransformation(radius.toFloat()))
60
+ },
61
+ second = { radii ->
62
+ // RoundedCornersTransformation rejects negative radii; treat them as square.
63
+ val topLeft = (radii.topLeft?.toFloat() ?: 0f).coerceAtLeast(0f)
64
+ val topRight = (radii.topRight?.toFloat() ?: 0f).coerceAtLeast(0f)
65
+ val bottomLeft = (radii.bottomLeft?.toFloat() ?: 0f).coerceAtLeast(0f)
66
+ val bottomRight = (radii.bottomRight?.toFloat() ?: 0f).coerceAtLeast(0f)
67
+ if (topLeft > 0f || topRight > 0f || bottomLeft > 0f || bottomRight > 0f) {
68
+ add(RoundedCornersTransformation(topLeft, topRight, bottomLeft, bottomRight))
69
+ }
70
+ },
71
+ )
47
72
  }
48
73
  val request =
49
74
  ImageRequest.Builder(context)
@@ -64,6 +89,13 @@ class HybridNitroImagePipeline : HybridNitroImagePipelineSpec() {
64
89
  }
65
90
  null -> Unit // Coil defaults: both enabled
66
91
  }
92
+ // Ask the decoder for the target size so a large source is
93
+ // subsampled near it instead of decoded at full resolution;
94
+ // ResizeTransformation then makes the size exact.
95
+ resize?.let { (width, height) ->
96
+ size(width, height)
97
+ scale(Scale.FILL)
98
+ }
67
99
  }
68
100
  .allowHardware(true)
69
101
  .transformations(transformations)
@@ -0,0 +1,59 @@
1
+ package com.margelo.nitro.nitroimagepipeline.transform
2
+
3
+ import android.graphics.Bitmap
4
+ import android.graphics.Canvas
5
+ import android.graphics.Matrix
6
+ import android.graphics.Paint
7
+ import coil3.size.Size
8
+ import coil3.transform.Transformation
9
+ import kotlin.math.max
10
+
11
+ /**
12
+ * Scales the input to fill exactly [width] × [height] pixels and center-crops the overflow (CSS
13
+ * `object-fit: cover`), upscaling smaller sources. It runs before [BlurTransformation] and rounded
14
+ * corners so their pixel units refer to the final bitmap — matching Nuke's
15
+ * `ImageProcessors.Resize(contentMode: .aspectFill, crop: true)` on iOS.
16
+ */
17
+ class ResizeTransformation(
18
+ private val width: Int,
19
+ private val height: Int,
20
+ ) : Transformation() {
21
+
22
+ init {
23
+ require(width > 0 && height > 0) { "width and height must be > 0." }
24
+ }
25
+
26
+ override val cacheKey = "${ResizeTransformation::class.java.name}-$width-$height"
27
+
28
+ override suspend fun transform(input: Bitmap, size: Size): Bitmap {
29
+ val softwareInput =
30
+ if (input.config == Bitmap.Config.HARDWARE) input.copy(Bitmap.Config.ARGB_8888, false)
31
+ else input
32
+ if (softwareInput.width == width && softwareInput.height == height) return softwareInput
33
+
34
+ val scale =
35
+ max(width.toFloat() / softwareInput.width, height.toFloat() / softwareInput.height)
36
+ val matrix =
37
+ Matrix().apply {
38
+ setScale(scale, scale)
39
+ postTranslate(
40
+ (width - softwareInput.width * scale) / 2f,
41
+ (height - softwareInput.height * scale) / 2f,
42
+ )
43
+ }
44
+ val config = softwareInput.config ?: Bitmap.Config.ARGB_8888
45
+ val output = Bitmap.createBitmap(width, height, config)
46
+ Canvas(output)
47
+ .drawBitmap(softwareInput, matrix, Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG))
48
+ return output
49
+ }
50
+
51
+ override fun equals(other: Any?): Boolean {
52
+ if (this === other) return true
53
+ return other is ResizeTransformation && width == other.width && height == other.height
54
+ }
55
+
56
+ override fun hashCode(): Int = 31 * width + height
57
+
58
+ override fun toString() = "ResizeTransformation(width=$width, height=$height)"
59
+ }
@@ -117,11 +117,32 @@ class HybridNitroImagePipeline: HybridNitroImagePipelineSpec {
117
117
  }
118
118
 
119
119
  var processors: [any ImageProcessing] = []
120
+ // Resize first: blur sigma and corner radii are defined in pixels
121
+ // of the bitmap they run on, so they must see the final size.
122
+ if let resize = options?.resize, resize.width > 0, resize.height > 0 {
123
+ processors.append(ImageProcessors.Resize(
124
+ size: CGSize(width: resize.width, height: resize.height),
125
+ unit: .pixels,
126
+ contentMode: .aspectFill,
127
+ crop: true,
128
+ upscale: true
129
+ ))
130
+ }
120
131
  if let blur = options?.blur, blur > 0 {
121
132
  processors.append(GaussianBlurProcessor(sigma: blur))
122
133
  }
123
- if let cornerRadius = options?.cornerRadius, cornerRadius > 0 {
124
- processors.append(.roundedCorners(radius: cornerRadius))
134
+ switch options?.cornerRadius {
135
+ case .first(let radius):
136
+ if radius > 0 {
137
+ processors.append(.roundedCorners(radius: radius))
138
+ }
139
+ case .second(let radii):
140
+ let roundedCorners = RoundedCornersProcessor(radii: radii)
141
+ if roundedCorners.hasRounding {
142
+ processors.append(roundedCorners)
143
+ }
144
+ case nil:
145
+ break
125
146
  }
126
147
 
127
148
  let imgRequest = ImageRequest(
@@ -0,0 +1,121 @@
1
+ //
2
+ // RoundedCornersProcessor.swift
3
+ // NitroImagePipeline
4
+ //
5
+ // Bakes independent per-corner radii into the bitmap. Nuke's built-in
6
+ // ImageProcessors.RoundedCorners only supports one uniform radius, so the
7
+ // asymmetric case clips through a hand-built CGPath instead.
8
+ //
9
+
10
+ import CoreGraphics
11
+ import Foundation
12
+ import Nuke
13
+ import UIKit
14
+
15
+ /// Nuke processor that rounds each corner with its own radius, measured in
16
+ /// pixels of the bitmap it receives (like `ImageProcessors.RoundedCorners`
17
+ /// with `unit: .points` on the scale-1 images the pipeline decodes). Runs
18
+ /// after `ImageProcessors.Resize` when `Options.resize` is set, so the radii
19
+ /// refer to the final output size.
20
+ struct RoundedCornersProcessor: ImageProcessing {
21
+ let topLeft: CGFloat
22
+ let topRight: CGFloat
23
+ let bottomLeft: CGFloat
24
+ let bottomRight: CGFloat
25
+
26
+ init(radii: CornerRadii) {
27
+ // Negative radii would make CGPath arcs undefined; treat them as square.
28
+ topLeft = CGFloat(max(radii.topLeft ?? 0, 0))
29
+ topRight = CGFloat(max(radii.topRight ?? 0, 0))
30
+ bottomLeft = CGFloat(max(radii.bottomLeft ?? 0, 0))
31
+ bottomRight = CGFloat(max(radii.bottomRight ?? 0, 0))
32
+ }
33
+
34
+ var hasRounding: Bool {
35
+ topLeft > 0 || topRight > 0 || bottomLeft > 0 || bottomRight > 0
36
+ }
37
+
38
+ var identifier: String {
39
+ "com.nitroimagepipeline.roundedCorners?tl=\(topLeft),tr=\(topRight),bl=\(bottomLeft),br=\(bottomRight)"
40
+ }
41
+
42
+ var hashableIdentifier: AnyHashable { identifier }
43
+
44
+ func process(_ image: PlatformImage) -> PlatformImage? {
45
+ let size = image.size
46
+ guard size.width > 0, size.height > 0 else { return image }
47
+
48
+ let format = UIGraphicsImageRendererFormat()
49
+ format.scale = image.scale
50
+ format.opaque = false
51
+
52
+ let rect = CGRect(origin: .zero, size: size)
53
+ return UIGraphicsImageRenderer(size: size, format: format).image { context in
54
+ context.cgContext.addPath(Self.clipPath(
55
+ in: rect,
56
+ topLeft: topLeft,
57
+ topRight: topRight,
58
+ bottomLeft: bottomLeft,
59
+ bottomRight: bottomRight
60
+ ))
61
+ context.cgContext.clip()
62
+ image.draw(in: rect)
63
+ }
64
+ }
65
+
66
+ /// A rounded-rect outline with independent corner radii, clamped the way
67
+ /// CSS `border-radius` clamps: if two radii on one edge overlap, all four
68
+ /// scale down proportionally until they fit.
69
+ static func clipPath(
70
+ in rect: CGRect,
71
+ topLeft: CGFloat,
72
+ topRight: CGFloat,
73
+ bottomLeft: CGFloat,
74
+ bottomRight: CGFloat
75
+ ) -> CGPath {
76
+ var scale: CGFloat = 1
77
+ for (edge, pair) in [
78
+ (rect.width, topLeft + topRight),
79
+ (rect.width, bottomLeft + bottomRight),
80
+ (rect.height, topLeft + bottomLeft),
81
+ (rect.height, topRight + bottomRight),
82
+ ] where pair > edge {
83
+ scale = min(scale, edge / pair)
84
+ }
85
+ let topLeft = topLeft * scale
86
+ let topRight = topRight * scale
87
+ let bottomLeft = bottomLeft * scale
88
+ let bottomRight = bottomRight * scale
89
+
90
+ // addArc(tangent1End:tangent2End:radius: 0) degenerates to a line
91
+ // through the corner, so square corners need no special-casing.
92
+ let path = CGMutablePath()
93
+ path.move(to: CGPoint(x: rect.minX + topLeft, y: rect.minY))
94
+ path.addLine(to: CGPoint(x: rect.maxX - topRight, y: rect.minY))
95
+ path.addArc(
96
+ tangent1End: CGPoint(x: rect.maxX, y: rect.minY),
97
+ tangent2End: CGPoint(x: rect.maxX, y: rect.minY + topRight),
98
+ radius: topRight
99
+ )
100
+ path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - bottomRight))
101
+ path.addArc(
102
+ tangent1End: CGPoint(x: rect.maxX, y: rect.maxY),
103
+ tangent2End: CGPoint(x: rect.maxX - bottomRight, y: rect.maxY),
104
+ radius: bottomRight
105
+ )
106
+ path.addLine(to: CGPoint(x: rect.minX + bottomLeft, y: rect.maxY))
107
+ path.addArc(
108
+ tangent1End: CGPoint(x: rect.minX, y: rect.maxY),
109
+ tangent2End: CGPoint(x: rect.minX, y: rect.maxY - bottomLeft),
110
+ radius: bottomLeft
111
+ )
112
+ path.addLine(to: CGPoint(x: rect.minX, y: rect.minY + topLeft))
113
+ path.addArc(
114
+ tangent1End: CGPoint(x: rect.minX, y: rect.minY),
115
+ tangent2End: CGPoint(x: rect.minX + topLeft, y: rect.minY),
116
+ radius: topLeft
117
+ )
118
+ path.closeSubpath()
119
+ return path
120
+ }
121
+ }
@@ -20,6 +20,7 @@ function useImage({
20
20
  url,
21
21
  blur = 0,
22
22
  cornerRadius = 0,
23
+ resize,
23
24
  cache
24
25
  }) {
25
26
  const [image, setImage] = (0, _react.useState)({
@@ -27,6 +28,19 @@ function useImage({
27
28
  error: undefined
28
29
  });
29
30
  const loadedUrlRef = (0, _react.useRef)(url);
31
+
32
+ // Split the option into primitives so an inline `{ topLeft: 24, ... }`
33
+ // literal (new identity every render) doesn't re-trigger the effect.
34
+ const isUniformRadius = typeof cornerRadius === 'number';
35
+ const uniformRadius = isUniformRadius ? cornerRadius : 0;
36
+ const {
37
+ topLeft = 0,
38
+ topRight = 0,
39
+ bottomLeft = 0,
40
+ bottomRight = 0
41
+ } = isUniformRadius ? {} : cornerRadius;
42
+ const resizeWidth = resize?.width ?? 0;
43
+ const resizeHeight = resize?.height ?? 0;
30
44
  (0, _react.useEffect)(() => {
31
45
  let cancelled = false;
32
46
  // Only reset to the loading state when the URL changes; for same-URL
@@ -43,7 +57,16 @@ function useImage({
43
57
  try {
44
58
  const result = await NitroImagePipeline.loadImage(url, {
45
59
  blur,
46
- cornerRadius,
60
+ cornerRadius: isUniformRadius ? uniformRadius : {
61
+ topLeft,
62
+ topRight,
63
+ bottomLeft,
64
+ bottomRight
65
+ },
66
+ resize: resizeWidth > 0 && resizeHeight > 0 ? {
67
+ width: resizeWidth,
68
+ height: resizeHeight
69
+ } : undefined,
47
70
  cache
48
71
  });
49
72
  if (!cancelled) {
@@ -65,7 +88,7 @@ function useImage({
65
88
  return () => {
66
89
  cancelled = true;
67
90
  };
68
- }, [url, blur, cornerRadius, cache]);
91
+ }, [url, blur, isUniformRadius, uniformRadius, topLeft, topRight, bottomLeft, bottomRight, resizeWidth, resizeHeight, cache]);
69
92
  return image;
70
93
  }
71
94
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_react","require","_reactNativeNitroModules","NitroImagePipeline","exports","NitroModules","createHybridObject","useImage","url","blur","cornerRadius","cache","image","setImage","useState","undefined","error","loadedUrlRef","useRef","useEffect","cancelled","current","result","loadImage","e","Error"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAEA,IAAAC,wBAAA,GAAAD,OAAA;AAUO,MAAME,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,GAC7BE,qCAAY,CAACC,kBAAkB,CAAyB,oBAAoB,CAAC;AAmB/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,QAAQA,CAAC;EACvBC,GAAG;EACHC,IAAI,GAAG,CAAC;EACRC,YAAY,GAAG,CAAC;EAChBC;AAWF,CAAC,EAAU;EACT,MAAM,CAACC,KAAK,EAAEC,QAAQ,CAAC,GAAG,IAAAC,eAAQ,EAAS;IACzCF,KAAK,EAAEG,SAAS;IAChBC,KAAK,EAAED;EACT,CAAC,CAAC;EACF,MAAME,YAAY,GAAG,IAAAC,aAAM,EAACV,GAAG,CAAC;EAEhC,IAAAW,gBAAS,EAAC,MAAM;IACd,IAAIC,SAAS,GAAG,KAAK;IACrB;IACA;IACA;IACA,IAAIH,YAAY,CAACI,OAAO,KAAKb,GAAG,EAAE;MAChCS,YAAY,CAACI,OAAO,GAAGb,GAAG;MAC1BK,QAAQ,CAAC;QAAED,KAAK,EAAEG,SAAS;QAAEC,KAAK,EAAED;MAAU,CAAC,CAAC;IAClD;IAEA,CAAC,YAAY;MACX,IAAI;QACF,MAAMO,MAAM,GAAG,MAAMnB,kBAAkB,CAACoB,SAAS,CAACf,GAAG,EAAE;UACrDC,IAAI;UACJC,YAAY;UACZC;QACF,CAAC,CAAC;QAEF,IAAI,CAACS,SAAS,EAAE;UACdP,QAAQ,CAAC;YAAED,KAAK,EAAEU,MAAM;YAAEN,KAAK,EAAED;UAAU,CAAC,CAAC;QAC/C;MACF,CAAC,CAAC,OAAOS,CAAC,EAAE;QACV,MAAMR,KAAK,GAAGQ,CAAC,YAAYC,KAAK,GAAGD,CAAC,GAAG,IAAIC,KAAK,CAAC,GAAGD,CAAC,EAAE,CAAC;QACxD,IAAI,CAACJ,SAAS,EAAE;UACdP,QAAQ,CAAC;YAAED,KAAK,EAAEG,SAAS;YAAEC,KAAK,EAAEA;UAAM,CAAC,CAAC;QAC9C;MACF;IACF,CAAC,EAAE,CAAC;IAEJ,OAAO,MAAM;MACXI,SAAS,GAAG,IAAI;IAClB,CAAC;EACH,CAAC,EAAE,CAACZ,GAAG,EAAEC,IAAI,EAAEC,YAAY,EAAEC,KAAK,CAAC,CAAC;EAEpC,OAAOC,KAAK;AACd","ignoreList":[]}
1
+ {"version":3,"names":["_react","require","_reactNativeNitroModules","NitroImagePipeline","exports","NitroModules","createHybridObject","useImage","url","blur","cornerRadius","resize","cache","image","setImage","useState","undefined","error","loadedUrlRef","useRef","isUniformRadius","uniformRadius","topLeft","topRight","bottomLeft","bottomRight","resizeWidth","width","resizeHeight","height","useEffect","cancelled","current","result","loadImage","e","Error"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAEA,IAAAC,wBAAA,GAAAD,OAAA;AAYO,MAAME,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,GAC7BE,qCAAY,CAACC,kBAAkB,CAAyB,oBAAoB,CAAC;AAmB/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,QAAQA,CAAC;EACvBC,GAAG;EACHC,IAAI,GAAG,CAAC;EACRC,YAAY,GAAG,CAAC;EAChBC,MAAM;EACNC;AAuBF,CAAC,EAAU;EACT,MAAM,CAACC,KAAK,EAAEC,QAAQ,CAAC,GAAG,IAAAC,eAAQ,EAAS;IACzCF,KAAK,EAAEG,SAAS;IAChBC,KAAK,EAAED;EACT,CAAC,CAAC;EACF,MAAME,YAAY,GAAG,IAAAC,aAAM,EAACX,GAAG,CAAC;;EAEhC;EACA;EACA,MAAMY,eAAe,GAAG,OAAOV,YAAY,KAAK,QAAQ;EACxD,MAAMW,aAAa,GAAGD,eAAe,GAAGV,YAAY,GAAG,CAAC;EACxD,MAAM;IACJY,OAAO,GAAG,CAAC;IACXC,QAAQ,GAAG,CAAC;IACZC,UAAU,GAAG,CAAC;IACdC,WAAW,GAAG;EAChB,CAAC,GAAGL,eAAe,GAAG,CAAC,CAAC,GAAGV,YAAY;EACvC,MAAMgB,WAAW,GAAGf,MAAM,EAAEgB,KAAK,IAAI,CAAC;EACtC,MAAMC,YAAY,GAAGjB,MAAM,EAAEkB,MAAM,IAAI,CAAC;EAExC,IAAAC,gBAAS,EAAC,MAAM;IACd,IAAIC,SAAS,GAAG,KAAK;IACrB;IACA;IACA;IACA,IAAIb,YAAY,CAACc,OAAO,KAAKxB,GAAG,EAAE;MAChCU,YAAY,CAACc,OAAO,GAAGxB,GAAG;MAC1BM,QAAQ,CAAC;QAAED,KAAK,EAAEG,SAAS;QAAEC,KAAK,EAAED;MAAU,CAAC,CAAC;IAClD;IAEA,CAAC,YAAY;MACX,IAAI;QACF,MAAMiB,MAAM,GAAG,MAAM9B,kBAAkB,CAAC+B,SAAS,CAAC1B,GAAG,EAAE;UACrDC,IAAI;UACJC,YAAY,EAAEU,eAAe,GACzBC,aAAa,GACb;YAAEC,OAAO;YAAEC,QAAQ;YAAEC,UAAU;YAAEC;UAAY,CAAC;UAClDd,MAAM,EACJe,WAAW,GAAG,CAAC,IAAIE,YAAY,GAAG,CAAC,GAC/B;YAAED,KAAK,EAAED,WAAW;YAAEG,MAAM,EAAED;UAAa,CAAC,GAC5CZ,SAAS;UACfJ;QACF,CAAC,CAAC;QAEF,IAAI,CAACmB,SAAS,EAAE;UACdjB,QAAQ,CAAC;YAAED,KAAK,EAAEoB,MAAM;YAAEhB,KAAK,EAAED;UAAU,CAAC,CAAC;QAC/C;MACF,CAAC,CAAC,OAAOmB,CAAC,EAAE;QACV,MAAMlB,KAAK,GAAGkB,CAAC,YAAYC,KAAK,GAAGD,CAAC,GAAG,IAAIC,KAAK,CAAC,GAAGD,CAAC,EAAE,CAAC;QACxD,IAAI,CAACJ,SAAS,EAAE;UACdjB,QAAQ,CAAC;YAAED,KAAK,EAAEG,SAAS;YAAEC,KAAK,EAAEA;UAAM,CAAC,CAAC;QAC9C;MACF;IACF,CAAC,EAAE,CAAC;IAEJ,OAAO,MAAM;MACXc,SAAS,GAAG,IAAI;IAClB,CAAC;EACH,CAAC,EAAE,CACDvB,GAAG,EACHC,IAAI,EACJW,eAAe,EACfC,aAAa,EACbC,OAAO,EACPC,QAAQ,EACRC,UAAU,EACVC,WAAW,EACXC,WAAW,EACXE,YAAY,EACZhB,KAAK,CACN,CAAC;EAEF,OAAOC,KAAK;AACd","ignoreList":[]}
@@ -15,6 +15,7 @@ export function useImage({
15
15
  url,
16
16
  blur = 0,
17
17
  cornerRadius = 0,
18
+ resize,
18
19
  cache
19
20
  }) {
20
21
  const [image, setImage] = useState({
@@ -22,6 +23,19 @@ export function useImage({
22
23
  error: undefined
23
24
  });
24
25
  const loadedUrlRef = useRef(url);
26
+
27
+ // Split the option into primitives so an inline `{ topLeft: 24, ... }`
28
+ // literal (new identity every render) doesn't re-trigger the effect.
29
+ const isUniformRadius = typeof cornerRadius === 'number';
30
+ const uniformRadius = isUniformRadius ? cornerRadius : 0;
31
+ const {
32
+ topLeft = 0,
33
+ topRight = 0,
34
+ bottomLeft = 0,
35
+ bottomRight = 0
36
+ } = isUniformRadius ? {} : cornerRadius;
37
+ const resizeWidth = resize?.width ?? 0;
38
+ const resizeHeight = resize?.height ?? 0;
25
39
  useEffect(() => {
26
40
  let cancelled = false;
27
41
  // Only reset to the loading state when the URL changes; for same-URL
@@ -38,7 +52,16 @@ export function useImage({
38
52
  try {
39
53
  const result = await NitroImagePipeline.loadImage(url, {
40
54
  blur,
41
- cornerRadius,
55
+ cornerRadius: isUniformRadius ? uniformRadius : {
56
+ topLeft,
57
+ topRight,
58
+ bottomLeft,
59
+ bottomRight
60
+ },
61
+ resize: resizeWidth > 0 && resizeHeight > 0 ? {
62
+ width: resizeWidth,
63
+ height: resizeHeight
64
+ } : undefined,
42
65
  cache
43
66
  });
44
67
  if (!cancelled) {
@@ -60,7 +83,7 @@ export function useImage({
60
83
  return () => {
61
84
  cancelled = true;
62
85
  };
63
- }, [url, blur, cornerRadius, cache]);
86
+ }, [url, blur, isUniformRadius, uniformRadius, topLeft, topRight, bottomLeft, bottomRight, resizeWidth, resizeHeight, cache]);
64
87
  return image;
65
88
  }
66
89
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["useEffect","useRef","useState","NitroModules","NitroImagePipeline","createHybridObject","useImage","url","blur","cornerRadius","cache","image","setImage","undefined","error","loadedUrlRef","cancelled","current","result","loadImage","e","Error"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AAEnD,SAASC,YAAY,QAAQ,4BAA4B;AAUzD,OAAO,MAAMC,kBAAkB,GAC7BD,YAAY,CAACE,kBAAkB,CAAyB,oBAAoB,CAAC;AAmB/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,QAAQA,CAAC;EACvBC,GAAG;EACHC,IAAI,GAAG,CAAC;EACRC,YAAY,GAAG,CAAC;EAChBC;AAWF,CAAC,EAAU;EACT,MAAM,CAACC,KAAK,EAAEC,QAAQ,CAAC,GAAGV,QAAQ,CAAS;IACzCS,KAAK,EAAEE,SAAS;IAChBC,KAAK,EAAED;EACT,CAAC,CAAC;EACF,MAAME,YAAY,GAAGd,MAAM,CAACM,GAAG,CAAC;EAEhCP,SAAS,CAAC,MAAM;IACd,IAAIgB,SAAS,GAAG,KAAK;IACrB;IACA;IACA;IACA,IAAID,YAAY,CAACE,OAAO,KAAKV,GAAG,EAAE;MAChCQ,YAAY,CAACE,OAAO,GAAGV,GAAG;MAC1BK,QAAQ,CAAC;QAAED,KAAK,EAAEE,SAAS;QAAEC,KAAK,EAAED;MAAU,CAAC,CAAC;IAClD;IAEA,CAAC,YAAY;MACX,IAAI;QACF,MAAMK,MAAM,GAAG,MAAMd,kBAAkB,CAACe,SAAS,CAACZ,GAAG,EAAE;UACrDC,IAAI;UACJC,YAAY;UACZC;QACF,CAAC,CAAC;QAEF,IAAI,CAACM,SAAS,EAAE;UACdJ,QAAQ,CAAC;YAAED,KAAK,EAAEO,MAAM;YAAEJ,KAAK,EAAED;UAAU,CAAC,CAAC;QAC/C;MACF,CAAC,CAAC,OAAOO,CAAC,EAAE;QACV,MAAMN,KAAK,GAAGM,CAAC,YAAYC,KAAK,GAAGD,CAAC,GAAG,IAAIC,KAAK,CAAC,GAAGD,CAAC,EAAE,CAAC;QACxD,IAAI,CAACJ,SAAS,EAAE;UACdJ,QAAQ,CAAC;YAAED,KAAK,EAAEE,SAAS;YAAEC,KAAK,EAAEA;UAAM,CAAC,CAAC;QAC9C;MACF;IACF,CAAC,EAAE,CAAC;IAEJ,OAAO,MAAM;MACXE,SAAS,GAAG,IAAI;IAClB,CAAC;EACH,CAAC,EAAE,CAACT,GAAG,EAAEC,IAAI,EAAEC,YAAY,EAAEC,KAAK,CAAC,CAAC;EAEpC,OAAOC,KAAK;AACd","ignoreList":[]}
1
+ {"version":3,"names":["useEffect","useRef","useState","NitroModules","NitroImagePipeline","createHybridObject","useImage","url","blur","cornerRadius","resize","cache","image","setImage","undefined","error","loadedUrlRef","isUniformRadius","uniformRadius","topLeft","topRight","bottomLeft","bottomRight","resizeWidth","width","resizeHeight","height","cancelled","current","result","loadImage","e","Error"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AAEnD,SAASC,YAAY,QAAQ,4BAA4B;AAYzD,OAAO,MAAMC,kBAAkB,GAC7BD,YAAY,CAACE,kBAAkB,CAAyB,oBAAoB,CAAC;AAmB/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,QAAQA,CAAC;EACvBC,GAAG;EACHC,IAAI,GAAG,CAAC;EACRC,YAAY,GAAG,CAAC;EAChBC,MAAM;EACNC;AAuBF,CAAC,EAAU;EACT,MAAM,CAACC,KAAK,EAAEC,QAAQ,CAAC,GAAGX,QAAQ,CAAS;IACzCU,KAAK,EAAEE,SAAS;IAChBC,KAAK,EAAED;EACT,CAAC,CAAC;EACF,MAAME,YAAY,GAAGf,MAAM,CAACM,GAAG,CAAC;;EAEhC;EACA;EACA,MAAMU,eAAe,GAAG,OAAOR,YAAY,KAAK,QAAQ;EACxD,MAAMS,aAAa,GAAGD,eAAe,GAAGR,YAAY,GAAG,CAAC;EACxD,MAAM;IACJU,OAAO,GAAG,CAAC;IACXC,QAAQ,GAAG,CAAC;IACZC,UAAU,GAAG,CAAC;IACdC,WAAW,GAAG;EAChB,CAAC,GAAGL,eAAe,GAAG,CAAC,CAAC,GAAGR,YAAY;EACvC,MAAMc,WAAW,GAAGb,MAAM,EAAEc,KAAK,IAAI,CAAC;EACtC,MAAMC,YAAY,GAAGf,MAAM,EAAEgB,MAAM,IAAI,CAAC;EAExC1B,SAAS,CAAC,MAAM;IACd,IAAI2B,SAAS,GAAG,KAAK;IACrB;IACA;IACA;IACA,IAAIX,YAAY,CAACY,OAAO,KAAKrB,GAAG,EAAE;MAChCS,YAAY,CAACY,OAAO,GAAGrB,GAAG;MAC1BM,QAAQ,CAAC;QAAED,KAAK,EAAEE,SAAS;QAAEC,KAAK,EAAED;MAAU,CAAC,CAAC;IAClD;IAEA,CAAC,YAAY;MACX,IAAI;QACF,MAAMe,MAAM,GAAG,MAAMzB,kBAAkB,CAAC0B,SAAS,CAACvB,GAAG,EAAE;UACrDC,IAAI;UACJC,YAAY,EAAEQ,eAAe,GACzBC,aAAa,GACb;YAAEC,OAAO;YAAEC,QAAQ;YAAEC,UAAU;YAAEC;UAAY,CAAC;UAClDZ,MAAM,EACJa,WAAW,GAAG,CAAC,IAAIE,YAAY,GAAG,CAAC,GAC/B;YAAED,KAAK,EAAED,WAAW;YAAEG,MAAM,EAAED;UAAa,CAAC,GAC5CX,SAAS;UACfH;QACF,CAAC,CAAC;QAEF,IAAI,CAACgB,SAAS,EAAE;UACdd,QAAQ,CAAC;YAAED,KAAK,EAAEiB,MAAM;YAAEd,KAAK,EAAED;UAAU,CAAC,CAAC;QAC/C;MACF,CAAC,CAAC,OAAOiB,CAAC,EAAE;QACV,MAAMhB,KAAK,GAAGgB,CAAC,YAAYC,KAAK,GAAGD,CAAC,GAAG,IAAIC,KAAK,CAAC,GAAGD,CAAC,EAAE,CAAC;QACxD,IAAI,CAACJ,SAAS,EAAE;UACdd,QAAQ,CAAC;YAAED,KAAK,EAAEE,SAAS;YAAEC,KAAK,EAAEA;UAAM,CAAC,CAAC;QAC9C;MACF;IACF,CAAC,EAAE,CAAC;IAEJ,OAAO,MAAM;MACXY,SAAS,GAAG,IAAI;IAClB,CAAC;EACH,CAAC,EAAE,CACDpB,GAAG,EACHC,IAAI,EACJS,eAAe,EACfC,aAAa,EACbC,OAAO,EACPC,QAAQ,EACRC,UAAU,EACVC,WAAW,EACXC,WAAW,EACXE,YAAY,EACZd,KAAK,CACN,CAAC;EAEF,OAAOC,KAAK;AACd","ignoreList":[]}
@@ -1,6 +1,6 @@
1
1
  import type { Image } from 'react-native-nitro-image';
2
- import type { CacheOption, NitroImagePipeline as NitroImagePipelineSpec, Options } from './specs/nitro-image-toolkit.nitro';
3
- export type { CacheOption, Options };
2
+ import type { CacheOption, CornerRadii, NitroImagePipeline as NitroImagePipelineSpec, Options, ResizeOptions } from './specs/nitro-image-toolkit.nitro';
3
+ export type { CacheOption, CornerRadii, Options, ResizeOptions };
4
4
  export declare const NitroImagePipeline: NitroImagePipelineSpec;
5
5
  type Result = {
6
6
  image: undefined;
@@ -20,15 +20,27 @@ type Result = {
20
20
  * const { image, error } = useImage({ filePath: '/tmp/image.jpg' })
21
21
  * ```
22
22
  */
23
- export declare function useImage({ url, blur, cornerRadius, cache, }: {
23
+ export declare function useImage({ url, blur, cornerRadius, resize, cache, }: {
24
24
  url: string;
25
25
  /**
26
26
  * Gaussian blur strength, as the standard deviation (sigma) of the blur in
27
- * source-image pixels. Matches across iOS and Android; roughly half of
28
- * React Native's `blurRadius`.
27
+ * source-image pixels (of the resized bitmap when `resize` is set). Matches
28
+ * across iOS and Android; roughly half of React Native's `blurRadius`.
29
29
  */
30
30
  blur?: number;
31
- cornerRadius?: number;
31
+ /**
32
+ * Corner radius in pixels of the loaded bitmap. Pass a single number for
33
+ * uniform rounding, or per-corner radii (inline object literals are fine —
34
+ * the hook compares the radii by value, not identity). Pair with `resize`
35
+ * so the radii apply at the size you display instead of the source size.
36
+ */
37
+ cornerRadius?: number | CornerRadii;
38
+ /**
39
+ * Resize the bitmap to exactly this size in pixels (aspect-fill,
40
+ * center-crop) before blur/rounding. Typically your display size in points
41
+ * multiplied by `PixelRatio.get()`. Inline object literals are fine.
42
+ */
43
+ resize?: ResizeOptions;
32
44
  cache?: CacheOption;
33
45
  }): Result;
34
46
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAGtD,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,IAAI,sBAAsB,EAC5C,OAAO,EACR,MAAM,mCAAmC,CAAC;AAE3C,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAErC,eAAO,MAAM,kBAAkB,wBACgD,CAAC;AAEhF,KAAK,MAAM,GAEP;IACE,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;CAClB,GAED;IACE,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;CAClB,GAED;IACE,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEN;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,IAAQ,EACR,YAAgB,EAChB,KAAK,GACN,EAAE;IACD,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,GAAG,MAAM,CA0CT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAGtD,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,kBAAkB,IAAI,sBAAsB,EAC5C,OAAO,EACP,aAAa,EACd,MAAM,mCAAmC,CAAC;AAE3C,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;AAEjE,eAAO,MAAM,kBAAkB,wBACgD,CAAC;AAEhF,KAAK,MAAM,GAEP;IACE,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;CAClB,GAED;IACE,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;CAClB,GAED;IACE,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEN;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,IAAQ,EACR,YAAgB,EAChB,MAAM,EACN,KAAK,GACN,EAAE;IACD,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IACpC;;;;OAIG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,GAAG,MAAM,CAyET"}
@@ -1,19 +1,64 @@
1
1
  import type { Image } from 'react-native-nitro-image';
2
2
  import type { HybridObject } from 'react-native-nitro-modules';
3
3
  export type CacheOption = 'memory' | 'disk' | 'none';
4
+ /**
5
+ * Independent corner radii, in pixels of the loaded bitmap (see
6
+ * {@linkcode Options.cornerRadius}). Omitted corners stay square.
7
+ */
8
+ export interface CornerRadii {
9
+ topLeft?: number;
10
+ topRight?: number;
11
+ bottomLeft?: number;
12
+ bottomRight?: number;
13
+ }
14
+ /**
15
+ * Target bitmap size in pixels. The image is scaled to fill this size and
16
+ * center-cropped (like CSS `object-fit: cover`), upscaling if needed, so the
17
+ * result is exactly `width` × `height` pixels.
18
+ */
19
+ export interface ResizeOptions {
20
+ width: number;
21
+ height: number;
22
+ }
4
23
  export type Options = {
5
24
  /**
6
25
  * Gaussian blur strength, given as the standard deviation (sigma) of the
7
26
  * blur in **source-image pixels**. The same value on the same source image
8
27
  * produces the same result on iOS and Android.
9
28
  *
29
+ * When {@linkcode resize} is set, the blur runs after resizing, so sigma is
30
+ * in pixels of the resized bitmap instead.
31
+ *
10
32
  * React Native's `<Image blurRadius={n} />` is roughly `blur: n / 2`.
11
33
  *
12
34
  * @default 0 (no blur)
13
35
  */
14
36
  blur?: number;
15
37
  cache?: CacheOption;
16
- cornerRadius?: number;
38
+ /**
39
+ * Corner radius baked into the loaded bitmap, in **pixels of that bitmap**.
40
+ * Pass a single number to round all four corners uniformly, or a
41
+ * {@linkcode CornerRadii} object to round each corner independently (e.g. a
42
+ * "ticket" shape with larger bottom corners).
43
+ *
44
+ * Without {@linkcode resize} the radius applies to the full-resolution
45
+ * source image, so on a large photo displayed small the rounding shrinks
46
+ * along with it. To get corners sized for your layout, pass `resize` with
47
+ * your display size in pixels (points × screen scale) — the radii then
48
+ * apply to that final bitmap, 1:1 with what you see.
49
+ *
50
+ * @default 0 (square corners)
51
+ */
52
+ cornerRadius?: number | CornerRadii;
53
+ /**
54
+ * Resize the image to exactly this size in pixels (aspect-fill,
55
+ * center-crop) before `blur` and `cornerRadius` are applied. Besides making
56
+ * `cornerRadius` predictable, this avoids decoding and processing
57
+ * full-resolution bitmaps you only display small.
58
+ *
59
+ * @default undefined (keep the source size)
60
+ */
61
+ resize?: ResizeOptions;
17
62
  };
18
63
  export interface NitroImagePipeline extends HybridObject<{
19
64
  ios: 'swift';
@@ -1 +1 @@
1
- {"version":3,"file":"nitro-image-toolkit.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/nitro-image-toolkit.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AACrD,MAAM,MAAM,OAAO,GAAG;IACpB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,YAAY,CAAC;IACvD,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;CACnB,CAAC;IACA,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1D,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C;;;;OAIG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAG3D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B"}
1
+ {"version":3,"file":"nitro-image-toolkit.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/nitro-image-toolkit.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,OAAO,GAAG;IACpB;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IACpC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,YAAY,CAAC;IACvD,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;CACnB,CAAC;IACA,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1D,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C;;;;OAIG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAG3D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B"}
@@ -36,6 +36,7 @@ target_sources(
36
36
  ../nitrogen/generated/shared/c++/HybridNitroImagePipelineSpec.cpp
37
37
  # Android-specific Nitrogen C++ sources
38
38
  ../nitrogen/generated/android/c++/JHybridNitroImagePipelineSpec.cpp
39
+ ../nitrogen/generated/android/c++/JVariant_Double_CornerRadii.cpp
39
40
  )
40
41
 
41
42
  # From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake