From 14b2d3377a0feddb888292578187c44b5672c6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Kwas=CC=81niewski?= Date: Mon, 14 Oct 2024 15:00:16 +0200 Subject: [PATCH 1/8] feat: implement encode func --- cpp/react-native-basis-universal.cpp | 113 +++++++++++++++++- cpp/react-native-basis-universal.h | 4 +- example/ios/Podfile.lock | 7 ++ example/package.json | 3 +- .../react-native-blob-jsi-helper+0.3.1.patch | 15 +++ example/src/App.tsx | 37 ++++-- src/BasisEncoder.ts | 8 +- src/NativeBasisUniversal.ts | 8 +- yarn.lock | 11 ++ 9 files changed, 184 insertions(+), 22 deletions(-) create mode 100644 example/patches/react-native-blob-jsi-helper+0.3.1.patch diff --git a/cpp/react-native-basis-universal.cpp b/cpp/react-native-basis-universal.cpp index 9cd6fab..50af3ae 100644 --- a/cpp/react-native-basis-universal.cpp +++ b/cpp/react-native-basis-universal.cpp @@ -53,6 +53,82 @@ void ReactNativeBasisUniversal::setCreateKTX2File(jsi::Runtime &rt, jsi::Object encoder->m_params.m_create_ktx2_file = flag; } +int ReactNativeBasisUniversal::encode(jsi::Runtime &rt, jsi::Object handle, jsi::Object basisFileData) { + auto encoder = tryGetBasisEncoder(rt, handle); + + if (!basisFileData.isArrayBuffer(rt)) { + throw jsi::JSError(rt, "Image Array needs to be ArrayBuffer"); + } + + auto arrayBuffer = basisFileData.getArrayBuffer(rt); + auto data = arrayBuffer.data(rt); + + if (!basis_initialized_flag) + { + assert(0); + return 0; + } + + // We don't use threading for now, but the compressor needs a job pool. + job_pool jpool(1); + + // Initialize the compression parameters structure. This is the same structure that the command line tool fills in. + basis_compressor_params ¶ms = encoder->m_params; + + params.m_pJob_pool = &jpool; + + // Disabling multithreading for now, which sucks. + params.m_multithreading = false; + + params.m_status_output = params.m_debug; + + params.m_read_source_images = false; + params.m_write_output_basis_or_ktx2_files = false; + + basis_compressor comp; + + if (!comp.init(params)) + { + return 0; + } + + basis_compressor::error_code ec = comp.process(); + + if (ec != basis_compressor::cECSuccess) + { + // Something failed during compression. + return 0; + } + + if (params.m_create_ktx2_file) + { + // Compression succeeded, so copy the .ktx2 file bytes to the caller's buffer. + auto output = comp.get_output_basis_file(); + data = reinterpret_cast(output.data()); + + if (!data) { + return 0; + } + + // Return the file size of the .basis file in bytes. + return (uint32_t)comp.get_output_ktx2_file().size(); + } + else + { + auto output = comp.get_output_basis_file(); + + + // Compression succeeded, so copy the .basis file bytes to the caller's buffer. +// if (!copy_to_jsbuffer(dst_basis_file_js_val, comp.get_output_basis_file())) +// return 0; + + // Return the file size of the .basis file in bytes. + return (uint32_t)comp.get_output_basis_file().size(); + } + + return 0; +} + void ReactNativeBasisUniversal::setComputeStats(jsi::Runtime &rt, jsi::Object handle, bool flag) { auto encoder = tryGetBasisEncoder(rt, handle); encoder->m_params.m_compute_stats = flag; @@ -72,12 +148,45 @@ void ReactNativeBasisUniversal::setQualityLevel(jsi::Runtime &rt, jsi::Object ha } -void ReactNativeBasisUniversal::setSliceSourceImage(jsi::Runtime &rt, jsi::Object handle, int sliceIndex, jsi::Object imageArray, int width, int height, bool isPng) { - if (imageArray.isArrayBuffer(rt)) { +bool ReactNativeBasisUniversal::setSliceSourceImage(jsi::Runtime &rt, jsi::Object handle, int sliceIndex, jsi::Object imageArray, int width, int height, bool isPng) { + if (!imageArray.isArrayBuffer(rt)) { throw jsi::JSError(rt, "Image Array needs to be ArrayBuffer"); } + auto encoder = tryGetBasisEncoder(rt, handle); + + if (sliceIndex >= encoder->m_params.m_source_images.size()) + encoder->m_params.m_source_images.resize(sliceIndex + 1); + auto arrayBuffer = imageArray.getArrayBuffer(rt); auto data = arrayBuffer.data(rt); + + image& src_img = encoder->m_params.m_source_images[sliceIndex]; + + if (isPng) + { + // It's a PNG file, so try and parse it. + if (!load_png(data, arrayBuffer.size(rt), src_img, nullptr)) + { + return false; + } + + width = src_img.get_width(); + height = src_img.get_height(); + } + else + { + // It's a raw image, so check the buffer's size. + if (arrayBuffer.size(rt) != width * height * sizeof(uint32_t)) + { + return false; + } + + // Copy the raw image's data into our source image. + src_img.resize(width, height); + memcpy(src_img.get_ptr(), arrayBuffer.data(rt), width * height * sizeof(uint32_t)); + } + + return true; } void ReactNativeBasisUniversal::setPackUASTCFlags(jsi::Runtime &rt, jsi::Object handle, int flags) { diff --git a/cpp/react-native-basis-universal.h b/cpp/react-native-basis-universal.h index b9d8db6..eab3b6e 100644 --- a/cpp/react-native-basis-universal.h +++ b/cpp/react-native-basis-universal.h @@ -28,10 +28,10 @@ class ReactNativeBasisUniversal : public NativeBasisUniversalCxxSpecJSI { void setUASTC(jsi::Runtime &rt, jsi::Object handle, bool flag) override; void setCompressionLevel(jsi::Runtime &rt, jsi::Object handle, int level) override; void setKTX2UASTCSupercompression(jsi::Runtime &rt, jsi::Object handle, bool flag) override; - void setSliceSourceImage(jsi::Runtime &rt, jsi::Object handle, int sliceIndex, jsi::Object imageArray, int width, int height, bool isPng) override; + bool setSliceSourceImage(jsi::Runtime &rt, jsi::Object handle, int sliceIndex, jsi::Object imageArray, int width, int height, bool isPng) override; void setPackUASTCFlags(jsi::Runtime &rt, jsi::Object handle, int flags) override; void setQualityLevel(jsi::Runtime &rt, jsi::Object handle, int qualityLevel) override; - + int encode(jsi::Runtime &rt, jsi::Object handle, jsi::Object basisFileData) override; private: std::shared_ptr _callInvoker; diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index a5f2185..2bae829 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1230,6 +1230,9 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga + - react-native-blob-jsi-helper (0.3.1): + - React + - React-Core - React-nativeconfig (0.75.4) - React-NativeModulesApple (0.75.4): - glog @@ -1542,6 +1545,7 @@ DEPENDENCIES: - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) - react-native-basis-universal (from `../..`) + - react-native-blob-jsi-helper (from `../node_modules/react-native-blob-jsi-helper`) - React-nativeconfig (from `../node_modules/react-native/ReactCommon`) - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) @@ -1647,6 +1651,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" react-native-basis-universal: :path: "../.." + react-native-blob-jsi-helper: + :path: "../node_modules/react-native-blob-jsi-helper" React-nativeconfig: :path: "../node_modules/react-native/ReactCommon" React-NativeModulesApple: @@ -1742,6 +1748,7 @@ SPEC CHECKSUMS: React-Mapbuffer: b982d5bba94a8bc073bda48f0d27c9b28417fae3 React-microtasksnativemodule: 8fa285fed833a04a754bf575f8ded65fc240b88d react-native-basis-universal: 5a9b05e51cc23161be95911a7c442d0b204d189f + react-native-blob-jsi-helper: 1ead091c45c4883d363fe8d5c0230773fe66373b React-nativeconfig: 8c83d992b9cc7d75b5abe262069eaeea4349f794 React-NativeModulesApple: b8465afc883f5bf3fe8bac3767e394d581a5f123 React-perflogger: 59e1a3182dca2cee7b9f1f7aab204018d46d1914 diff --git a/example/package.json b/example/package.json index b9a80be..63a4cfd 100644 --- a/example/package.json +++ b/example/package.json @@ -12,7 +12,8 @@ }, "dependencies": { "react": "18.3.1", - "react-native": "0.75.4" + "react-native": "0.75.4", + "react-native-blob-jsi-helper": "^0.3.1" }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/example/patches/react-native-blob-jsi-helper+0.3.1.patch b/example/patches/react-native-blob-jsi-helper+0.3.1.patch new file mode 100644 index 0000000..0fcc65e --- /dev/null +++ b/example/patches/react-native-blob-jsi-helper+0.3.1.patch @@ -0,0 +1,15 @@ +diff --git a/node_modules/react-native-blob-jsi-helper/react-native-blob-jsi-helper.podspec b/node_modules/react-native-blob-jsi-helper/react-native-blob-jsi-helper.podspec +index 53ec31f..c47aba8 100644 +--- a/node_modules/react-native-blob-jsi-helper/react-native-blob-jsi-helper.podspec ++++ b/node_modules/react-native-blob-jsi-helper/react-native-blob-jsi-helper.podspec +@@ -15,6 +15,10 @@ Pod::Spec.new do |s| + + s.source_files = "ios/**/*.{h,m,mm}", "cpp/**/*.{h,cpp}" + ++ s.pod_target_xcconfig = { ++ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", ++ } ++ + s.dependency "React-Core" + s.dependency "React" + end diff --git a/example/src/App.tsx b/example/src/App.tsx index b3e2a30..551ca21 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -4,6 +4,14 @@ import { initializeBasis, BasisEncoder, } from '@callstack/react-native-basis-universal'; +import { getArrayBufferForBlob } from "react-native-blob-jsi-helper"; + +const fetchAndProcessFile = async (file: string): Promise => { + const x = await fetch(file) + const blob = await x.blob() + + return getArrayBufferForBlob(blob); +}; export default function App() { return ( @@ -11,21 +19,28 @@ export default function App() {