Skip to content

Commit 44fc2d4

Browse files
authored
feat: Add crop(...) (#8)
* feat: Add `crop(...)` * feat: Implement `crop(...)` on iOS * Update HybridImage.swift * feat: Implement `crop(...)` for Android * fix: Update react-native-nitro-modules to 0.26.3 * docs * Update README.md
1 parent 2820015 commit 44fc2d4

14 files changed

Lines changed: 188 additions & 7 deletions

File tree

β€ŽREADME.mdβ€Ž

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,18 @@ const resourceImage = loadImageFromResources('my-resource.jpg')
6363
const symbolImage = loadImageFromSymbol('star')
6464
```
6565

66+
#### Load with Options
67+
68+
When loading from a remote URL, you can tweak options such as `priority`:
69+
70+
```ts
71+
const image1 = await loadImageFromURLAsync(URL1, { priority: 'low' })
72+
const image2 = await loadImageFromURLAsync(URL2, { priority: 'high' })
73+
```
74+
6675
#### `ArrayBuffer`
6776

68-
The `Image` type can be converted to- and from- an `ArrayBuffer`:
77+
The `Image` type can be converted to- and from- an `ArrayBuffer`, which gives you access to the raw pixel data in ARGB format:
6978

7079
```ts
7180
const webImage = await loadImageFromURLAsync('https://picsum.photos/seed/123/400')
@@ -82,6 +91,15 @@ const webImage = await loadImageFromURLAsync('https://picsum.photos/seed/123/400
8291
const smaller = await webImage.resizeAsync(200, 200)
8392
```
8493

94+
#### Cropping
95+
96+
An `Image` can be cropped entirely in-memory, without ever writing to- or reading from- a file:
97+
98+
```ts
99+
const webImage = await loadImageFromURLAsync('https://picsum.photos/seed/123/400')
100+
const smaller = await webImage.cropAsync(100, 100, 50, 50)
101+
```
102+
85103
#### Saving
86104

87105
An in-memory `Image` object can also be written/saved to a file:

β€Žandroid/src/main/java/com/margelo/nitro/image/HybridImage.ktβ€Ž

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,41 @@ class HybridImage: HybridImageSpec {
6161
}
6262

6363
override fun resize(width: Double, height: Double): HybridImageSpec {
64+
if (width < 0) {
65+
throw Error("Width cannot be less than 0! (width: $width)")
66+
}
67+
if (height < 0) {
68+
throw Error("Height cannot be less than 0! (height: $height)")
69+
}
6470
val resizedBitmap = Bitmap.createScaledBitmap(bitmap, width.toInt(), height.toInt(), true)
6571
return HybridImage(resizedBitmap)
6672
}
67-
6873
override fun resizeAsync(width: Double, height: Double): Promise<HybridImageSpec> {
6974
return Promise.async { resize(width, height) }
7075
}
7176

77+
override fun crop(startX: Double, startY: Double, endX: Double, endY: Double): HybridImageSpec {
78+
val width = endX - startX
79+
val height = endY - startY
80+
if (width < 0) {
81+
throw Error("Width cannot be less than 0! (startX: $startX - endX: $endX = $width)")
82+
}
83+
if (height < 0) {
84+
throw Error("Height cannot be less than 0! (startY: $startY - endY: $endY = $height)")
85+
}
86+
val croppedBitmap = Bitmap.createBitmap(bitmap, startX.toInt(), startY.toInt(), width.toInt(), height.toInt())
87+
return HybridImage(croppedBitmap)
88+
}
89+
90+
override fun cropAsync(
91+
startX: Double,
92+
startY: Double,
93+
endX: Double,
94+
endY: Double
95+
): Promise<HybridImageSpec> {
96+
return Promise.async { crop(startX, startY, endX, endY) }
97+
}
98+
7299
override fun saveToFileAsync(
73100
path: String,
74101
format: ImageFormat,

β€Žbun.lockβ€Ž

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žios/HybridImage.swiftβ€Ž

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ class HybridImage: HybridImageSpec {
3636
}
3737

3838
func resize(width: Double, height: Double) throws -> any HybridImageSpec {
39+
guard width > 0 else {
40+
throw RuntimeError.error(withMessage: "Width cannot be less than 0! (width: \(width))")
41+
}
42+
guard height > 0 else {
43+
throw RuntimeError.error(withMessage: "Height cannot be less than 0! (height: \(height))")
44+
}
3945
let targetSize = CGSize(width: width, height: height)
4046

4147
let renderer = UIGraphicsImageRenderer(size: targetSize)
@@ -52,6 +58,34 @@ class HybridImage: HybridImageSpec {
5258
}
5359
}
5460

61+
func crop(startX: Double, startY: Double, endX: Double, endY: Double) throws -> any HybridImageSpec {
62+
let targetWidth = endX - startX
63+
let targetHeight = endY - startY
64+
guard targetWidth > 0 else {
65+
throw RuntimeError.error(withMessage: "Width cannot be less than 0! (startX: \(startX) - endX: \(endX) = \(targetWidth))")
66+
}
67+
guard targetHeight > 0 else {
68+
throw RuntimeError.error(withMessage: "Height cannot be less than 0! (startY: \(startY) - endY: \(endY) = \(targetHeight))")
69+
}
70+
guard let cgImage = uiImage.cgImage else {
71+
throw RuntimeError.error(withMessage: "This image does not have an underlying .cgImage!")
72+
}
73+
74+
let targetRect = CGRect(origin: CGPoint(x: startX, y: startY),
75+
size: CGSize(width: width, height: height))
76+
guard let croppedCgImage = cgImage.cropping(to: targetRect) else {
77+
throw RuntimeError.error(withMessage: "Failed to crop CGImage to \(targetRect)!")
78+
}
79+
let croppedUiImage = UIImage(cgImage: croppedCgImage)
80+
return HybridImage(uiImage: croppedUiImage)
81+
}
82+
83+
func cropAsync(startX: Double, startY: Double, endX: Double, endY: Double) throws -> Promise<any HybridImageSpec> {
84+
return Promise.async {
85+
return try self.crop(startX: startX, startY: startY, endX: endX, endY: endY)
86+
}
87+
}
88+
5589
private func saveImage(to path: String, format: ImageFormat, quality: Double) throws {
5690
guard let data = uiImage.getData(in: format, quality: quality) else {
5791
throw RuntimeError.error(withMessage: "Failed to get Image data in format \(format.stringValue) with quality \(quality)!")

β€Žnitrogen/generated/android/c++/JHybridImageSpec.cppβ€Ž

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žnitrogen/generated/android/c++/JHybridImageSpec.hppβ€Ž

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žnitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridImageSpec.ktβ€Ž

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žnitrogen/generated/ios/c++/HybridImageSpecSwift.hppβ€Ž

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žnitrogen/generated/ios/swift/HybridImageSpec.swiftβ€Ž

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žnitrogen/generated/ios/swift/HybridImageSpec_cxx.swiftβ€Ž

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
Β (0)