Skip to content

Commit 2820015

Browse files
authored
fix: Make toArrayBuffer() return raw RGBA data on iOS too (#7)
* fix: Make `toArrayBuffer()` return raw RGBA data on iOS too * feat: Add some docs * use ARGB on iOS too
1 parent b9736f6 commit 2820015

4 files changed

Lines changed: 74 additions & 6 deletions

File tree

example/ios/Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,7 +1866,7 @@ DEPENDENCIES:
18661866
- glog (from `../../node_modules/react-native/third-party-podspecs/glog.podspec`)
18671867
- hermes-engine (from `../../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
18681868
- NitroImage (from `../node_modules/react-native-nitro-image`)
1869-
- NitroModules (from `../../node_modules/react-native-nitro-modules`)
1869+
- NitroModules (from `../node_modules/react-native-nitro-modules`)
18701870
- RCT-Folly (from `../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
18711871
- RCT-Folly/Fabric (from `../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
18721872
- RCTDeprecation (from `../../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`)
@@ -1963,7 +1963,7 @@ EXTERNAL SOURCES:
19631963
NitroImage:
19641964
:path: "../node_modules/react-native-nitro-image"
19651965
NitroModules:
1966-
:path: "../../node_modules/react-native-nitro-modules"
1966+
:path: "../node_modules/react-native-nitro-modules"
19671967
RCT-Folly:
19681968
:podspec: "../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
19691969
RCTDeprecation:

ios/HybridImage.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ class HybridImage: HybridImageSpec {
2727
}
2828

2929
func toArrayBuffer() throws -> ArrayBufferHolder {
30-
guard let data = uiImage.pngData() else {
31-
throw RuntimeError.error(withMessage: "Failed to convert UIImage to png data!")
32-
}
33-
return try ArrayBufferHolder.copy(data: data)
30+
return try uiImage.toRawRgbaArrayBuffer()
3431
}
3532
func toArrayBufferAsync() throws -> Promise<ArrayBufferHolder> {
3633
return Promise.async {

ios/UIImage+rawRgbaData.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import UIKit
2+
import CoreGraphics
3+
import NitroModules
4+
5+
extension UIImage {
6+
/**
7+
* Returns raw RGBA data of this UIImage
8+
*/
9+
func toRawRgbaArrayBuffer() throws -> ArrayBufferHolder {
10+
guard let cg = self.cgImage else {
11+
throw RuntimeError.error(withMessage: "Failed to get Image's underlying cgImage!")
12+
}
13+
14+
let width = cg.width
15+
let height = cg.height
16+
let bytesPerPixel = 4
17+
let bytesPerRow = bytesPerPixel * width
18+
let bitsPerComponent = 8
19+
20+
// Allocate a Data buffer of the right size
21+
let totalSize = width * height * bytesPerPixel
22+
let arrayBuffer = ArrayBufferHolder.allocate(size: totalSize)
23+
24+
// Create a RGB-premultiplied-first context (aka ARGB)
25+
let colorSpace = CGColorSpaceCreateDeviceRGB()
26+
let bitmapInfo = CGImageAlphaInfo.premultipliedFirst.rawValue
27+
28+
guard let ctx = CGContext(
29+
data: arrayBuffer.data,
30+
width: width,
31+
height: height,
32+
bitsPerComponent: bitsPerComponent,
33+
bytesPerRow: bytesPerRow,
34+
space: colorSpace,
35+
bitmapInfo: bitmapInfo
36+
) else {
37+
throw RuntimeError.error(withMessage: "Failed to create CGContext for \(width)x\(height) RGBA Image!")
38+
}
39+
40+
// Draw the Image into the CGContext
41+
let rect = CGRect(x: 0, y: 0, width: width, height: height)
42+
ctx.draw(cg, in: rect)
43+
44+
return arrayBuffer
45+
}
46+
}

src/specs/Image.nitro.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,47 @@ export interface Image
77
readonly width: number
88
readonly height: number
99

10+
/**
11+
* Returns an array buffer containing the raw pixel data of the Image.
12+
* Raw pixel data is always in `ARGB` format;
13+
* ```
14+
* [
15+
* A1, R1, G1, B1,
16+
* A2, R2, G2, B2,
17+
* ...
18+
* ]
19+
* ```
20+
*/
1021
toArrayBuffer(): ArrayBuffer
1122
toArrayBufferAsync(): Promise<ArrayBuffer>
1223

24+
/**
25+
* Resizes this Image into a new image with the new given {@linkcode width} and {@linkcode height}.
26+
*/
1327
resize(width: number, height: number): Image
1428
resizeAsync(width: number, height: number): Promise<Image>
1529

30+
/**
31+
* Saves this image in the given {@linkcode ImageFormat} to the given {@linkcode path}.
32+
*/
1633
saveToFileAsync(
1734
path: string,
1835
format: ImageFormat,
1936
quality: number
2037
): Promise<void>
38+
/**
39+
* Saves this image in the given {@linkcode ImageFormat} to a temporary file, and return it's path.
40+
*/
2141
saveToTemporaryFileAsync(
2242
format: ImageFormat,
2343
quality: number
2444
): Promise<string>
2545

46+
/**
47+
* Encodes this Image into a ThumbHash.
48+
* To convert the returned ThumbHash to a string, use `thumbHashToBase64String(...)`.
49+
* @note To keep this efficient, {@linkcode resize} this image to a small size (<100x100) first.
50+
*/
2651
toThumbHash(): ArrayBuffer
2752
toThumbHashAsync(): Promise<ArrayBuffer>
2853
}

0 commit comments

Comments
 (0)