diff --git a/dependency-patches/README.md b/dependency-patches/README.md index fe53f8d4a44..14206ca0dda 100644 --- a/dependency-patches/README.md +++ b/dependency-patches/README.md @@ -10,6 +10,7 @@ | 依赖 | 用途 | | --- | --- | +| `expo-image-manipulator@57.0.14` | 修复 iOS HDR / 10-bit HEIC 图片在方向归一化时因原生 `CGContext` 参数不兼容而抛出 `ERR_IMAGE_CONTEXT_LOST`;正常方向直接复用原图,其余方向交给 `UIGraphicsImageRenderer`。同类问题与真机验证见 [`tloncorp/tlon-apps#5951`](https://github.com/tloncorp/tlon-apps/pull/5951),待 Expo 上游提供等价修复后移除。 | | `expo-paste-input@0.2.2` | 优化移动端粘贴图片的处理时序,将耗时的解码、压缩和写盘移出 UI 线程,并补充加载中与失败事件。 | | `harmonyos-sans-sc-webfont-splitted` | 移除依赖按语言全局覆盖 `font-family` 的规则,由 Cindy 自己决定界面字体。 | | `react-native@0.85.3` | 回移 Yoga 对 `display: none` 与 `display: contents` 测量过程的布局状态修复,避免 Fabric 布局阶段因错误的 owner 关系触发断言崩溃(上游 `6fa330693fba313a2fe1121545c1efd558b60983`、`2546ce4d8219050fcd1bf432c7c830c9fd70c9af`)。移动端 iOS 通过 `expo-build-properties` 的 `buildReactNativeFromSource` 编译该补丁,不能改回预编译 RN Core。 | diff --git a/dependency-patches/expo-image-manipulator@57.0.14.patch b/dependency-patches/expo-image-manipulator@57.0.14.patch new file mode 100644 index 00000000000..109d6ed62c1 --- /dev/null +++ b/dependency-patches/expo-image-manipulator@57.0.14.patch @@ -0,0 +1,79 @@ +diff --git a/ios/Transformers/ImageFixOrientationTransformer.swift b/ios/Transformers/ImageFixOrientationTransformer.swift +index c3e3b66eb6b5b0ef75431c96bf292d4fae004606..9e9e6503a09771896936c4d823dd28e9d03b51df 100644 +--- a/ios/Transformers/ImageFixOrientationTransformer.swift ++++ b/ios/Transformers/ImageFixOrientationTransformer.swift +@@ -6,70 +6,12 @@ + */ + internal struct ImageFixOrientationTransformer: ImageTransformer { + func transform(image: UIImage) async throws -> UIImage { +- guard let cgImage = image.cgImage else { +- throw ImageNotFoundException() +- } +- guard var colorSpace = cgImage.colorSpace else { +- // That should never happen as `colorSpace` is empty only when the image is a mask. +- throw ImageColorSpaceNotFoundException() +- } +- if !colorSpace.supportsOutput { +- colorSpace = CGColorSpaceCreateDeviceRGB() +- } +- +- var transform = CGAffineTransform.identity +- +- switch image.imageOrientation { +- case .down, .downMirrored: +- transform = transform.translatedBy(x: image.size.width, y: image.size.height) +- transform = transform.rotated(by: Double.pi) +- case .left, .leftMirrored: +- transform = transform.translatedBy(x: image.size.width, y: 0) +- transform = transform.rotated(by: Double.pi / 2) +- case .right, .rightMirrored: +- transform = transform.translatedBy(x: 0, y: image.size.height) +- transform = transform.rotated(by: -Double.pi / 2) +- default: +- break +- } +- +- switch image.imageOrientation { +- case .upMirrored, .downMirrored: +- transform = transform.translatedBy(x: image.size.width, y: 0) +- transform = transform.scaledBy(x: -1, y: 1) +- case .leftMirrored, .rightMirrored: +- transform = transform.translatedBy(x: image.size.height, y: 0) +- transform = transform.scaledBy(x: -1, y: 1) +- default: +- break +- } +- +- let context = CGContext( +- data: nil, +- width: Int(image.size.width), +- height: Int(image.size.height), +- bitsPerComponent: cgImage.bitsPerComponent, +- bytesPerRow: 0, +- space: colorSpace, +- bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue +- ) +- +- guard let context = context else { +- throw ImageContextLostException() +- } +- +- context.concatenate(transform) +- +- switch image.imageOrientation { +- case .left, .leftMirrored, .right, .rightMirrored: +- context.draw(cgImage, in: CGRect(x: 0, y: 0, width: image.size.height, height: image.size.width)) +- default: +- context.draw(cgImage, in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)) ++ if image.imageOrientation == .up { ++ return image + } + +- guard let newCGImage = context.makeImage() else { +- throw ImageDrawingFailedException() ++ return drawInNewContext(size: image.size) { _ in ++ image.draw(in: CGRect(origin: .zero, size: image.size)) + } +- return UIImage(cgImage: newCGImage) + } + } diff --git a/package.json b/package.json index 30aac573034..e05660e060c 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "react-native@0.85.3": "dependency-patches/react-native@0.85.3.patch", "react-native-uitextview@2.2.0": "dependency-patches/react-native-uitextview@2.2.0.patch", "react-native-webview@13.16.1": "dependency-patches/react-native-webview@13.16.1.patch", + "expo-image-manipulator@57.0.14": "dependency-patches/expo-image-manipulator@57.0.14.patch", "expo-paste-input@0.2.2": "dependency-patches/expo-paste-input@0.2.2.patch" }, "allowUnusedPatches": true diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 260e29340ec..4b20edca9af 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,6 +19,9 @@ overrides: builder-util-runtime: ^9.7.0 patchedDependencies: + expo-image-manipulator@57.0.14: + hash: 78594ca2235bdbbee2665f37b86d4e1e892733c4f9bd38fa7085338b90486e2b + path: dependency-patches/expo-image-manipulator@57.0.14.patch expo-paste-input@0.2.2: hash: 53be555646735a171c1624f074ef30e5ca897a7b8893724bc2d0d51682f769d8 path: dependency-patches/expo-paste-input@0.2.2.patch @@ -658,7 +661,7 @@ importers: version: 57.0.3(expo@57.0.17)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.3))(react@19.2.3) expo-image-manipulator: specifier: ~57.0.14 - version: 57.0.14(expo@57.0.17) + version: 57.0.14(patch_hash=78594ca2235bdbbee2665f37b86d4e1e892733c4f9bd38fa7085338b90486e2b)(expo@57.0.17) expo-image-picker: specifier: ^57.0.14 version: 57.0.14(expo@57.0.17) @@ -16857,7 +16860,7 @@ snapshots: dependencies: expo: 57.0.17(@babel/core@7.29.7)(@expo/dom-webview@57.0.1)(@expo/metro-runtime@57.0.14)(expo-router@57.0.17)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native-webview@13.16.1(patch_hash=4f76ca2497d14d136ef6ff35060f4c35b57319a3edf53fa334b82771a9405c16)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.3))(react@19.2.3))(react-native-worklets@0.10.1(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - expo-image-manipulator@57.0.14(expo@57.0.17): + expo-image-manipulator@57.0.14(patch_hash=78594ca2235bdbbee2665f37b86d4e1e892733c4f9bd38fa7085338b90486e2b)(expo@57.0.17): dependencies: expo: 57.0.17(@babel/core@7.29.7)(@expo/dom-webview@57.0.1)(@expo/metro-runtime@57.0.14)(expo-router@57.0.17)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native-webview@13.16.1(patch_hash=4f76ca2497d14d136ef6ff35060f4c35b57319a3edf53fa334b82771a9405c16)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.3))(react@19.2.3))(react-native-worklets@0.10.1(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) expo-image-loader: 57.0.1(expo@57.0.17)