diff --git a/README.md b/README.md index 010b665..5911d21 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,19 @@ const result = await MediaToolkit.compressImage(imageUri, { }); ``` +### Split image into grid + +```typescript +const parts = await MediaToolkit.splitImage(imageUri, { + rows: 3, + columns: 4, + quality: 100, // optional, defaults to 100 for lossy formats +}); + +console.log(parts.length); // 12 +console.log(parts[0].uri, parts[0].width, parts[0].height); +``` + ### Flip image ```typescript @@ -296,6 +309,19 @@ All options are optional. Pass an empty object `{}` to use all defaults. | `format` | `string` | `'jpeg'` | Output format: `'jpeg'` \| `'png'` \| `'webp'` | | `outputPath` | `string` | temp file | Absolute path for the output file | +### `splitImage(uri, options): Promise` + +Splits the source image into a `rows x columns` grid using original pixel dimensions. Tiles are not resized. When format is omitted, the native layer keeps the source format when supported; iOS falls back to PNG for unsupported source encoders such as WebP. + +| Option | Type | Required | Description | +|---|---|---|---| +| `rows` | `number` | **Required** | Number of output rows | +| `columns` | `number` | **Required** | Number of output columns | +| `format` | `string` | Optional | Force output format: `'jpeg'` \| `'png'` \| `'webp'` | +| `quality` | `number` | Optional | Lossy encode quality (0–100). Defaults to `100` | +| `outputDir` | `string` | Optional | Absolute output directory for generated tiles | +| `prefix` | `string` | Optional | Filename prefix for generated tiles | + ### `flipImage(uri, options): Promise` ### `flipVideo(uri, options): Promise` diff --git a/README.vi.md b/README.vi.md index 9cf3f59..5520345 100644 --- a/README.vi.md +++ b/README.vi.md @@ -103,6 +103,19 @@ const result = await MediaToolkit.compressImage(imageUri, { }); ``` +### Chia ảnh theo lưới + +```typescript +const parts = await MediaToolkit.splitImage(imageUri, { + rows: 3, + columns: 4, + quality: 100, // tuỳ chọn, mặc định 100 với format lossy +}); + +console.log(parts.length); // 12 +console.log(parts[0].uri, parts[0].width, parts[0].height); +``` + ### Lật ảnh ```typescript @@ -296,6 +309,19 @@ Tất cả options đều là tuỳ chọn. Có thể truyền object rỗng `{} | `format` | `string` | `'jpeg'` | Định dạng output: `'jpeg'` \| `'png'` \| `'webp'` | | `outputPath` | `string` | file tạm | Đường dẫn tuyệt đối file output | +### `splitImage(uri, options): Promise` + +Chia ảnh nguồn thành lưới `rows x columns` theo đúng pixel gốc, không resize từng mảnh. Nếu không truyền `format`, native sẽ giữ format nguồn khi hỗ trợ; trên iOS sẽ fallback sang PNG nếu format nguồn không encode lại được như WebP. + +| Option | Kiểu | Bắt buộc | Mô tả | +|---|---|---|---| +| `rows` | `number` | **Bắt buộc** | Số hàng đầu ra | +| `columns` | `number` | **Bắt buộc** | Số cột đầu ra | +| `format` | `string` | Tuỳ chọn | Ép định dạng output: `'jpeg'` \| `'png'` \| `'webp'` | +| `quality` | `number` | Tuỳ chọn | Chất lượng encode lossy (0–100). Mặc định `100` | +| `outputDir` | `string` | Tuỳ chọn | Thư mục output tuyệt đối cho các tile | +| `prefix` | `string` | Tuỳ chọn | Tiền tố tên file cho các tile | + ### `flipImage(uri, options): Promise` ### `flipVideo(uri, options): Promise` diff --git a/android/src/main/java/com/mediatoolkit/HybridMediaToolkit.kt b/android/src/main/java/com/mediatoolkit/HybridMediaToolkit.kt index f350708..aee3f67 100644 --- a/android/src/main/java/com/mediatoolkit/HybridMediaToolkit.kt +++ b/android/src/main/java/com/mediatoolkit/HybridMediaToolkit.kt @@ -15,6 +15,7 @@ import com.margelo.nitro.com.mediatoolkit.RotateOptions import com.margelo.nitro.com.mediatoolkit.SpeedOptions import com.margelo.nitro.com.mediatoolkit.ExtractAudioOptions import com.margelo.nitro.com.mediatoolkit.GeneratePreviewOptions +import com.margelo.nitro.com.mediatoolkit.SplitImageOptions import com.margelo.nitro.com.mediatoolkit.ThumbnailOptions import com.margelo.nitro.com.mediatoolkit.ThumbnailResult import com.margelo.nitro.com.mediatoolkit.TrimAndCropOptions @@ -74,6 +75,20 @@ class HybridMediaToolkit : HybridMediaToolkitSpec() { } } + override fun splitImage(uri: String, options: SplitImageOptions): Promise> { + return Promise.async(scope) { + ImageProcessor.splitImage( + uri, + options.rows.toInt(), + options.columns.toInt(), + options.format, + (options.quality ?: 100.0).toInt(), + options.outputDir, + options.prefix + ).map { it.toMediaResult() }.toTypedArray() + } + } + override fun flipImage(uri: String, options: FlipOptions): Promise { return Promise.async(scope) { val raw = ImageProcessor.flipImage( diff --git a/android/src/main/java/com/mediatoolkit/ImageProcessor.kt b/android/src/main/java/com/mediatoolkit/ImageProcessor.kt index fc44290..52e69dc 100644 --- a/android/src/main/java/com/mediatoolkit/ImageProcessor.kt +++ b/android/src/main/java/com/mediatoolkit/ImageProcessor.kt @@ -9,6 +9,7 @@ import androidx.exifinterface.media.ExifInterface import java.io.File import java.io.FileOutputStream import java.util.UUID +import java.util.Locale /** * Image crop and compress using Android Bitmap API. @@ -237,6 +238,56 @@ internal object ImageProcessor { return buildResult(out, bmp, mime, 0) } + fun splitImage( + uri: String, + rows: Int, + columns: Int, + format: String?, + quality: Int, + outputDir: String?, + prefix: String? + ): List> { + if (rows <= 0 || columns <= 0) { + throw MediaToolkitException.InvalidInput("rows and columns must be greater than 0") + } + + val path = uriToPath(uri) + var bmp = BitmapFactory.decodeFile(path) + ?: throw MediaToolkitException.InvalidInput("Cannot decode image: $uri") + + bmp = fixExifOrientation(bmp, path) + + try { + val resolvedFormat = resolveImageFormat(format, path) + val targetDir = resolveOutputDirectory(outputDir) + val filePrefix = prefix?.takeIf { it.isNotBlank() } ?: "split_${UUID.randomUUID()}" + val qualityValue = quality.coerceIn(0, 100) + val results = mutableListOf>() + + for (row in 0 until rows) { + val top = bmp.height * row / rows + val bottom = bmp.height * (row + 1) / rows + val tileHeight = (bottom - top).coerceAtLeast(1) + + for (column in 0 until columns) { + val left = bmp.width * column / columns + val right = bmp.width * (column + 1) / columns + val tileWidth = (right - left).coerceAtLeast(1) + val tile = Bitmap.createBitmap(bmp, left, top, tileWidth, tileHeight) + val out = File(targetDir, "${filePrefix}_r${row + 1}_c${column + 1}.${resolvedFormat.ext}").absolutePath + + writeBitmap(tile, out, resolvedFormat, qualityValue) + results.add(buildResult(out, tile, resolvedFormat.mime, 0)) + tile.recycle() + } + } + + return results + } finally { + bmp.recycle() + } + } + // ─── Helpers ───────────────────────────────────────────────────────────── fun uriToPath(uri: String): String = @@ -248,6 +299,65 @@ internal object ImageProcessor { return "$dir/${UUID.randomUUID()}.$ext" } + private data class EncodedImageFormat( + val ext: String, + val mime: String, + val compressFormat: Bitmap.CompressFormat + ) + + private fun resolveImageFormat(requestedFormat: String?, path: String): EncodedImageFormat { + return when ((requestedFormat?.lowercase(Locale.US) ?: inferSourceFormat(path))) { + "png" -> EncodedImageFormat("png", "image/png", Bitmap.CompressFormat.PNG) + "webp" -> EncodedImageFormat( + "webp", + "image/webp", + if (android.os.Build.VERSION.SDK_INT >= 30) { + Bitmap.CompressFormat.WEBP_LOSSLESS + } else { + Bitmap.CompressFormat.WEBP + } + ) + "jpg", "jpeg" -> EncodedImageFormat("jpg", "image/jpeg", Bitmap.CompressFormat.JPEG) + else -> EncodedImageFormat("jpg", "image/jpeg", Bitmap.CompressFormat.JPEG) + } + } + + private fun inferSourceFormat(path: String): String { + val ext = path.substringAfterLast('.', "").lowercase(Locale.US) + return when (ext) { + "png" -> "png" + "webp" -> "webp" + "jpg", "jpeg" -> "jpeg" + else -> "jpeg" + } + } + + private fun resolveOutputDirectory(outputDir: String?): File { + val dir = if (outputDir.isNullOrBlank()) { + File(System.getProperty("java.io.tmpdir") ?: "/data/local/tmp") + } else { + File(outputDir) + } + if (!dir.exists()) { + dir.mkdirs() + } + return dir + } + + private fun writeBitmap( + bmp: Bitmap, + path: String, + format: EncodedImageFormat, + quality: Int + ) { + val written = FileOutputStream(path).use { fos -> + bmp.compress(format.compressFormat, quality, fos) + } + if (!written) { + throw MediaToolkitException.ProcessingFailed("Could not encode split image") + } + } + private fun fixExifOrientation(bmp: Bitmap, path: String): Bitmap { return try { val exif = ExifInterface(path) diff --git a/example/src/App.tsx b/example/src/App.tsx index 1d0be66..8a3bb7a 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -127,6 +127,7 @@ export default function App() { // ── Result & UI state ──────────────────────────────────────────────────── const [result, setResult] = useState(null); + const [splitResults, setSplitResults] = useState([]); const [loading, setLoading] = useState(false); const [log, setLog] = useState([]); const [opLabel, setOpLabel] = useState(''); @@ -137,6 +138,8 @@ export default function App() { const [muteAudio, setMuteAudio] = useState(false); const [imgQuality, setImgQuality] = useState('80'); const [imgMaxWidth, setImgMaxWidth] = useState('1080'); + const [splitRows, setSplitRows] = useState('2'); + const [splitColumns, setSplitColumns] = useState('2'); const [gifMaxWidth, setGifMaxWidth] = useState('0'); const srcPlayer = useVideoPlayer(srcUri, (player) => { @@ -189,6 +192,7 @@ export default function App() { setLoading(true); setResult(null); + setSplitResults([]); setOpLabel(label); try { const r = await fn(); @@ -224,6 +228,7 @@ export default function App() { height: a.height, }); setResult(null); + setSplitResults([]); setCrop(DEF_CROP); addLog(`📷 ${a.fileName ?? 'image'}`); } @@ -241,6 +246,7 @@ export default function App() { setSrcUri(a.uri); setSrcType('video'); setResult(null); + setSplitResults([]); setSrcMeta({ fileName: a.fileName, fileSize: a.fileSize, @@ -266,6 +272,7 @@ export default function App() { setSrcUri(uri); setSrcType('video'); setResult(null); + setSplitResults([]); setVcrop(DEF_CROP); setVidNat({ w: 0, h: 0 }); setVidDur(durationMs > 0 ? durationMs : 30000); @@ -377,6 +384,36 @@ export default function App() { ); }; + const splitImageGrid = async () => { + setScreen('home'); + const rows = parseInt(splitRows, 10); + const columns = parseInt(splitColumns, 10); + if (!rows || !columns || rows < 1 || columns < 1) { + Alert.alert('Invalid grid', 'Rows and columns must be greater than 0.'); + return; + } + + setLoading(true); + setResult(null); + setSplitResults([]); + setOpLabel('Split Image'); + try { + const parts = await MediaToolkit.splitImage(srcUri!, { + rows, + columns, + quality: 100, + }); + setSplitResults(parts); + addLog(`✅ Split Image → ${parts.length} tiles`); + } catch (e: any) { + addLog(`❌ Split Image: ${e?.message ?? e}`); + Alert.alert('Split Image failed', e?.message ?? String(e)); + } finally { + setLoading(false); + setOpLabel(''); + } + }; + const compressVid = () => { setScreen('home'); const size = parseFloat(targetSize) || 8.0; @@ -744,6 +781,47 @@ export default function App() { /> + + + Image Splitter + + Split by rows and columns without resizing source pixels + + + + + Rows + + + + Columns + + + + + + + Metadata (EXIF) @@ -1181,6 +1259,46 @@ export default function App() { )} + {splitResults.length > 0 && ( + + SPLIT RESULT + + {splitResults.length} tiles generated + + + {splitResults.map((item, index) => ( + + + + Tile {index + 1} + + {`${item.width}×${item.height}`} + {fmtSize(item.size)} + + ))} + + + )} + {/* Result */} {result && ( diff --git a/ios/HybridMediaToolkit.swift b/ios/HybridMediaToolkit.swift index 5ee1572..e0c0cae 100644 --- a/ios/HybridMediaToolkit.swift +++ b/ios/HybridMediaToolkit.swift @@ -42,6 +42,21 @@ class HybridMediaToolkit: HybridMediaToolkitSpec { } } + func splitImage(uri: String, options: SplitImageOptions) throws -> Promise<[MediaResult]> { + return Promise.parallel(queue) { + let raw = try ImageProcessor.splitImage( + uri: uri, + rows: options.rows, + columns: options.columns, + format: options.format, + quality: options.quality ?? 100, + outputDir: options.outputDir, + prefix: options.prefix + ) + return raw.map(makeMediaResult) + } + } + func flipImage(uri: String, options: FlipOptions) throws -> Promise { return Promise.parallel(queue) { let raw = try ImageProcessor.flipImage( diff --git a/ios/ImageProcessor.swift b/ios/ImageProcessor.swift index a4bc0ae..8ef035d 100644 --- a/ios/ImageProcessor.swift +++ b/ios/ImageProcessor.swift @@ -256,6 +256,69 @@ class ImageProcessor: NSObject { return result(path: out, image: resized, mime: mime) } + @objc + static func splitImage( + uri: String, + rows: Double, + columns: Double, + format: String?, + quality: Double, + outputDir: String?, + prefix: String? + ) throws -> [[String: Any]] { + let rowCount = Int(rows) + let columnCount = Int(columns) + guard rowCount > 0, columnCount > 0 else { + throw MediaToolkitError.invalidInput("rows and columns must be greater than 0") + } + + let path = uri.hasPrefix("file://") ? String(uri.dropFirst(7)) : uri + let url = URL(fileURLWithPath: path) + guard let source = CGImageSourceCreateWithURL(url as CFURL, nil) else { + throw MediaToolkitError.invalidInput("Cannot load image source at: \(uri)") + } + guard let image = loadImage(from: uri) else { + throw MediaToolkitError.invalidInput("Cannot load image at: \(uri)") + } + + let normalised = normaliseOrientation(image) + guard let cgImage = normalised.cgImage else { + throw MediaToolkitError.processingFailed("Could not access CGImage backing store") + } + + let encoding = resolveSplitEncoding(requestedFormat: format, source: source) + let directory = try resolveOutputDirectory(outputDir) + let basePrefix = prefix?.isEmpty == false ? prefix! : "split_\(UUID().uuidString)" + let clampedQuality = max(0, min(100, quality)) / 100.0 + var results: [[String: Any]] = [] + + for row in 0.. UIImage? { @@ -299,6 +362,71 @@ class ImageProcessor: NSObject { return (NSTemporaryDirectory() as NSString).appendingPathComponent(name) } + private struct SplitImageEncoding { + let ext: String + let mime: String + let kind: String + } + + private static func resolveSplitEncoding( + requestedFormat: String?, + source: CGImageSource + ) -> SplitImageEncoding { + let normalized = requestedFormat?.lowercased() + if normalized == "png" { + return SplitImageEncoding(ext: "png", mime: "image/png", kind: "png") + } + if normalized == "jpeg" || normalized == "jpg" { + return SplitImageEncoding(ext: "jpg", mime: "image/jpeg", kind: "jpeg") + } + if normalized == "webp" { + return SplitImageEncoding(ext: "png", mime: "image/png", kind: "png") + } + + let sourceType = CGImageSourceGetType(source) as String? + if let sourceType, let utType = UTType(sourceType) { + if utType.conforms(to: .png) { + return SplitImageEncoding(ext: "png", mime: "image/png", kind: "png") + } + if utType.conforms(to: .jpeg) { + return SplitImageEncoding(ext: "jpg", mime: "image/jpeg", kind: "jpeg") + } + } + + return SplitImageEncoding(ext: "jpg", mime: "image/jpeg", kind: "jpeg") + } + + private static func resolveOutputDirectory(_ outputDir: String?) throws -> URL { + if let outputDir, !outputDir.isEmpty { + let url = URL(fileURLWithPath: outputDir, isDirectory: true) + try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true) + return url + } + + let dir = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) + try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true) + return dir + } + + private static func encodeSplitImage( + _ image: UIImage, + encoding: SplitImageEncoding, + quality: Double + ) throws -> Data { + switch encoding.kind { + case "png": + if let data = image.pngData() { + return data + } + default: + if let data = image.jpegData(compressionQuality: quality) { + return data + } + } + + throw MediaToolkitError.processingFailed("Could not encode split image") + } + private static func result(path: String, image: UIImage, mime: String) -> [String: Any] { let size = (try? Data(contentsOf: URL(fileURLWithPath: path)).count) ?? 0 return [ diff --git a/nitrogen/generated/android/c++/JHybridMediaToolkitSpec.cpp b/nitrogen/generated/android/c++/JHybridMediaToolkitSpec.cpp index 35362d2..2263ec1 100644 --- a/nitrogen/generated/android/c++/JHybridMediaToolkitSpec.cpp +++ b/nitrogen/generated/android/c++/JHybridMediaToolkitSpec.cpp @@ -19,6 +19,8 @@ namespace margelo::nitro::mediatoolkit { struct LocationData; } namespace margelo::nitro::mediatoolkit { struct CropOptions; } // Forward declaration of `CompressImageOptions` to properly resolve imports. namespace margelo::nitro::mediatoolkit { struct CompressImageOptions; } +// Forward declaration of `SplitImageOptions` to properly resolve imports. +namespace margelo::nitro::mediatoolkit { struct SplitImageOptions; } // Forward declaration of `FlipOptions` to properly resolve imports. namespace margelo::nitro::mediatoolkit { struct FlipOptions; } // Forward declaration of `RotateOptions` to properly resolve imports. @@ -49,6 +51,7 @@ namespace margelo::nitro::mediatoolkit { struct GeneratePreviewOptions; } #include #include "JMediaResult.hpp" #include +#include #include "ThumbnailResult.hpp" #include "JThumbnailResult.hpp" #include "MediaMetadata.hpp" @@ -60,6 +63,8 @@ namespace margelo::nitro::mediatoolkit { struct GeneratePreviewOptions; } #include "JCropOptions.hpp" #include "CompressImageOptions.hpp" #include "JCompressImageOptions.hpp" +#include "SplitImageOptions.hpp" +#include "JSplitImageOptions.hpp" #include "FlipOptions.hpp" #include "JFlipOptions.hpp" #include "RotateOptions.hpp" @@ -150,6 +155,31 @@ namespace margelo::nitro::mediatoolkit { return __promise; }(); } + std::shared_ptr>> JHybridMediaToolkitSpec::splitImage(const std::string& uri, const SplitImageOptions& options) { + static const auto method = _javaPart->javaClassStatic()->getMethod(jni::alias_ref /* uri */, jni::alias_ref /* options */)>("splitImage"); + auto __result = method(_javaPart, jni::make_jstring(uri), JSplitImageOptions::fromCpp(options)); + return [&]() { + auto __promise = Promise>::create(); + __result->cthis()->addOnResolvedListener([=](const jni::alias_ref& __boxedResult) { + auto __result = jni::static_ref_cast>(__boxedResult); + __promise->resolve([&]() { + size_t __size = __result->size(); + std::vector __vector; + __vector.reserve(__size); + for (size_t __i = 0; __i < __size; __i++) { + auto __element = __result->getElement(__i); + __vector.push_back(__element->toCpp()); + } + return __vector; + }()); + }); + __result->cthis()->addOnRejectedListener([=](const jni::alias_ref& __throwable) { + jni::JniException __jniError(__throwable); + __promise->reject(std::make_exception_ptr(__jniError)); + }); + return __promise; + }(); + } std::shared_ptr> JHybridMediaToolkitSpec::flipImage(const std::string& uri, const FlipOptions& options) { static const auto method = _javaPart->javaClassStatic()->getMethod(jni::alias_ref /* uri */, jni::alias_ref /* options */)>("flipImage"); auto __result = method(_javaPart, jni::make_jstring(uri), JFlipOptions::fromCpp(options)); diff --git a/nitrogen/generated/android/c++/JHybridMediaToolkitSpec.hpp b/nitrogen/generated/android/c++/JHybridMediaToolkitSpec.hpp index a65ca8b..a657955 100644 --- a/nitrogen/generated/android/c++/JHybridMediaToolkitSpec.hpp +++ b/nitrogen/generated/android/c++/JHybridMediaToolkitSpec.hpp @@ -56,6 +56,7 @@ namespace margelo::nitro::mediatoolkit { // Methods std::shared_ptr> cropImage(const std::string& uri, const CropOptions& options) override; std::shared_ptr> compressImage(const std::string& uri, const CompressImageOptions& options) override; + std::shared_ptr>> splitImage(const std::string& uri, const SplitImageOptions& options) override; std::shared_ptr> flipImage(const std::string& uri, const FlipOptions& options) override; std::shared_ptr> rotateImage(const std::string& uri, const RotateOptions& options) override; std::shared_ptr> cropVideo(const std::string& uri, const VideoCropOptions& options) override; diff --git a/nitrogen/generated/android/c++/JSplitImageOptions.hpp b/nitrogen/generated/android/c++/JSplitImageOptions.hpp new file mode 100644 index 0000000..2b372ea --- /dev/null +++ b/nitrogen/generated/android/c++/JSplitImageOptions.hpp @@ -0,0 +1,78 @@ +/// +/// JSplitImageOptions.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include "SplitImageOptions.hpp" + +#include +#include + +namespace margelo::nitro::mediatoolkit { + + using namespace facebook; + + /** + * The C++ JNI bridge between the C++ struct "SplitImageOptions" and the the Kotlin data class "SplitImageOptions". + */ + struct JSplitImageOptions final: public jni::JavaClass { + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/com/mediatoolkit/SplitImageOptions;"; + + public: + /** + * Convert this Java/Kotlin-based struct to the C++ struct SplitImageOptions by copying all values to C++. + */ + [[maybe_unused]] + [[nodiscard]] + SplitImageOptions toCpp() const { + static const auto clazz = javaClassStatic(); + static const auto fieldRows = clazz->getField("rows"); + double rows = this->getFieldValue(fieldRows); + static const auto fieldColumns = clazz->getField("columns"); + double columns = this->getFieldValue(fieldColumns); + static const auto fieldFormat = clazz->getField("format"); + jni::local_ref format = this->getFieldValue(fieldFormat); + static const auto fieldQuality = clazz->getField("quality"); + jni::local_ref quality = this->getFieldValue(fieldQuality); + static const auto fieldOutputDir = clazz->getField("outputDir"); + jni::local_ref outputDir = this->getFieldValue(fieldOutputDir); + static const auto fieldPrefix = clazz->getField("prefix"); + jni::local_ref prefix = this->getFieldValue(fieldPrefix); + return SplitImageOptions( + rows, + columns, + format != nullptr ? std::make_optional(format->toStdString()) : std::nullopt, + quality != nullptr ? std::make_optional(quality->value()) : std::nullopt, + outputDir != nullptr ? std::make_optional(outputDir->toStdString()) : std::nullopt, + prefix != nullptr ? std::make_optional(prefix->toStdString()) : std::nullopt + ); + } + + public: + /** + * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. + */ + [[maybe_unused]] + static jni::local_ref fromCpp(const SplitImageOptions& value) { + using JSignature = JSplitImageOptions(double, double, jni::alias_ref, jni::alias_ref, jni::alias_ref, jni::alias_ref); + static const auto clazz = javaClassStatic(); + static const auto create = clazz->getStaticMethod("fromCpp"); + return create( + clazz, + value.rows, + value.columns, + value.format.has_value() ? jni::make_jstring(value.format.value()) : nullptr, + value.quality.has_value() ? jni::JDouble::valueOf(value.quality.value()) : nullptr, + value.outputDir.has_value() ? jni::make_jstring(value.outputDir.value()) : nullptr, + value.prefix.has_value() ? jni::make_jstring(value.prefix.value()) : nullptr + ); + } + }; + +} // namespace margelo::nitro::mediatoolkit diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CompressImageOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CompressImageOptions.kt index 18c8283..13981ea 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CompressImageOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CompressImageOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -35,6 +36,26 @@ data class CompressImageOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is CompressImageOptions) return false + return Objects.deepEquals(this.quality, other.quality) + && Objects.deepEquals(this.maxWidth, other.maxWidth) + && Objects.deepEquals(this.maxHeight, other.maxHeight) + && Objects.deepEquals(this.format, other.format) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + quality, + maxWidth, + maxHeight, + format, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CompressVideoOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CompressVideoOptions.kt index 2049b54..68f862a 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CompressVideoOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CompressVideoOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -41,6 +42,30 @@ data class CompressVideoOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is CompressVideoOptions) return false + return Objects.deepEquals(this.targetSizeInMB, other.targetSizeInMB) + && Objects.deepEquals(this.minResolution, other.minResolution) + && Objects.deepEquals(this.quality, other.quality) + && Objects.deepEquals(this.bitrate, other.bitrate) + && Objects.deepEquals(this.width, other.width) + && Objects.deepEquals(this.muteAudio, other.muteAudio) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + targetSizeInMB, + minResolution, + quality, + bitrate, + width, + muteAudio, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CropOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CropOptions.kt index 8d80999..45f5355 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CropOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/CropOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -35,6 +36,26 @@ data class CropOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is CropOptions) return false + return Objects.deepEquals(this.x, other.x) + && Objects.deepEquals(this.y, other.y) + && Objects.deepEquals(this.width, other.width) + && Objects.deepEquals(this.height, other.height) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + x, + y, + width, + height, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ExtractAudioOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ExtractAudioOptions.kt index f34baa7..037baad 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ExtractAudioOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ExtractAudioOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -23,6 +24,18 @@ data class ExtractAudioOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ExtractAudioOptions) return false + return Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/FlipOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/FlipOptions.kt index f4c5f3f..93c9c34 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/FlipOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/FlipOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -26,6 +27,20 @@ data class FlipOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is FlipOptions) return false + return Objects.deepEquals(this.direction, other.direction) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + direction, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/GeneratePreviewOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/GeneratePreviewOptions.kt index c960f7c..f71687d 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/GeneratePreviewOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/GeneratePreviewOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -35,6 +36,26 @@ data class GeneratePreviewOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is GeneratePreviewOptions) return false + return Objects.deepEquals(this.fps, other.fps) + && Objects.deepEquals(this.durationMs, other.durationMs) + && Objects.deepEquals(this.maxWidth, other.maxWidth) + && Objects.deepEquals(this.quality, other.quality) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + fps, + durationMs, + maxWidth, + quality, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/HybridMediaToolkitSpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/HybridMediaToolkitSpec.kt index a999513..bbf183b 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/HybridMediaToolkitSpec.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/HybridMediaToolkitSpec.kt @@ -37,6 +37,10 @@ abstract class HybridMediaToolkitSpec: HybridObject() { @Keep abstract fun compressImage(uri: String, options: CompressImageOptions): Promise + @DoNotStrip + @Keep + abstract fun splitImage(uri: String, options: SplitImageOptions): Promise> + @DoNotStrip @Keep abstract fun flipImage(uri: String, options: FlipOptions): Promise diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/LocationData.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/LocationData.kt index 0b81f43..0f9217c 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/LocationData.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/LocationData.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -26,6 +27,20 @@ data class LocationData( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is LocationData) return false + return Objects.deepEquals(this.latitude, other.latitude) + && Objects.deepEquals(this.longitude, other.longitude) + } + + override fun hashCode(): Int { + return arrayOf( + latitude, + longitude + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/MediaMetadata.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/MediaMetadata.kt index 5436b6f..7be315f 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/MediaMetadata.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/MediaMetadata.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -62,6 +63,44 @@ data class MediaMetadata( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is MediaMetadata) return false + return Objects.deepEquals(this.type, other.type) + && Objects.deepEquals(this.width, other.width) + && Objects.deepEquals(this.height, other.height) + && Objects.deepEquals(this.size, other.size) + && Objects.deepEquals(this.duration, other.duration) + && Objects.deepEquals(this.mime, other.mime) + && Objects.deepEquals(this.make, other.make) + && Objects.deepEquals(this.model, other.model) + && Objects.deepEquals(this.datetime, other.datetime) + && Objects.deepEquals(this.location, other.location) + && Objects.deepEquals(this.aperture, other.aperture) + && Objects.deepEquals(this.exposureTime, other.exposureTime) + && Objects.deepEquals(this.iso, other.iso) + && Objects.deepEquals(this.focalLength, other.focalLength) + } + + override fun hashCode(): Int { + return arrayOf( + type, + width, + height, + size, + duration, + mime, + make, + model, + datetime, + location, + aperture, + exposureTime, + iso, + focalLength + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/MediaResult.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/MediaResult.kt index 189867f..b7e3f8a 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/MediaResult.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/MediaResult.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -38,6 +39,28 @@ data class MediaResult( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is MediaResult) return false + return Objects.deepEquals(this.uri, other.uri) + && Objects.deepEquals(this.size, other.size) + && Objects.deepEquals(this.width, other.width) + && Objects.deepEquals(this.height, other.height) + && Objects.deepEquals(this.duration, other.duration) + && Objects.deepEquals(this.mime, other.mime) + } + + override fun hashCode(): Int { + return arrayOf( + uri, + size, + width, + height, + duration, + mime + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ProcessImageOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ProcessImageOptions.kt index a7c189c..8b007f0 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ProcessImageOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ProcessImageOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -41,6 +42,30 @@ data class ProcessImageOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ProcessImageOptions) return false + return Objects.deepEquals(this.cropX, other.cropX) + && Objects.deepEquals(this.cropY, other.cropY) + && Objects.deepEquals(this.cropWidth, other.cropWidth) + && Objects.deepEquals(this.cropHeight, other.cropHeight) + && Objects.deepEquals(this.flip, other.flip) + && Objects.deepEquals(this.rotation, other.rotation) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + cropX, + cropY, + cropWidth, + cropHeight, + flip, + rotation, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ProcessVideoOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ProcessVideoOptions.kt index 598a307..c957658 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ProcessVideoOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ProcessVideoOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -47,6 +48,34 @@ data class ProcessVideoOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ProcessVideoOptions) return false + return Objects.deepEquals(this.startTime, other.startTime) + && Objects.deepEquals(this.endTime, other.endTime) + && Objects.deepEquals(this.cropX, other.cropX) + && Objects.deepEquals(this.cropY, other.cropY) + && Objects.deepEquals(this.cropWidth, other.cropWidth) + && Objects.deepEquals(this.cropHeight, other.cropHeight) + && Objects.deepEquals(this.flip, other.flip) + && Objects.deepEquals(this.rotation, other.rotation) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + startTime, + endTime, + cropX, + cropY, + cropWidth, + cropHeight, + flip, + rotation, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/RotateOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/RotateOptions.kt index 77fecf0..217e8b7 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/RotateOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/RotateOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -26,6 +27,20 @@ data class RotateOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is RotateOptions) return false + return Objects.deepEquals(this.degrees, other.degrees) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + degrees, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/SpeedOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/SpeedOptions.kt index a94c303..d11665a 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/SpeedOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/SpeedOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -26,6 +27,20 @@ data class SpeedOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is SpeedOptions) return false + return Objects.deepEquals(this.speed, other.speed) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + speed, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/SplitImageOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/SplitImageOptions.kt new file mode 100644 index 0000000..02da7f6 --- /dev/null +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/SplitImageOptions.kt @@ -0,0 +1,76 @@ +/// +/// SplitImageOptions.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.com.mediatoolkit + +import androidx.annotation.Keep +import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects + + +/** + * Represents the JavaScript object/struct "SplitImageOptions". + */ +@DoNotStrip +@Keep +data class SplitImageOptions( + @DoNotStrip + @Keep + val rows: Double, + @DoNotStrip + @Keep + val columns: Double, + @DoNotStrip + @Keep + val format: String?, + @DoNotStrip + @Keep + val quality: Double?, + @DoNotStrip + @Keep + val outputDir: String?, + @DoNotStrip + @Keep + val prefix: String? +) { + /* primary constructor */ + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is SplitImageOptions) return false + return Objects.deepEquals(this.rows, other.rows) + && Objects.deepEquals(this.columns, other.columns) + && Objects.deepEquals(this.format, other.format) + && Objects.deepEquals(this.quality, other.quality) + && Objects.deepEquals(this.outputDir, other.outputDir) + && Objects.deepEquals(this.prefix, other.prefix) + } + + override fun hashCode(): Int { + return arrayOf( + rows, + columns, + format, + quality, + outputDir, + prefix + ).contentDeepHashCode() + } + + companion object { + /** + * Constructor called from C++ + */ + @DoNotStrip + @Keep + @Suppress("unused") + @JvmStatic + private fun fromCpp(rows: Double, columns: Double, format: String?, quality: Double?, outputDir: String?, prefix: String?): SplitImageOptions { + return SplitImageOptions(rows, columns, format, quality, outputDir, prefix) + } + } +} diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ThumbnailOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ThumbnailOptions.kt index 9075140..bd96497 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ThumbnailOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ThumbnailOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -32,6 +33,24 @@ data class ThumbnailOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ThumbnailOptions) return false + return Objects.deepEquals(this.timeMs, other.timeMs) + && Objects.deepEquals(this.quality, other.quality) + && Objects.deepEquals(this.maxWidth, other.maxWidth) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + timeMs, + quality, + maxWidth, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ThumbnailResult.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ThumbnailResult.kt index dc942d7..e8c27c9 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ThumbnailResult.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/ThumbnailResult.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -35,6 +36,26 @@ data class ThumbnailResult( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ThumbnailResult) return false + return Objects.deepEquals(this.uri, other.uri) + && Objects.deepEquals(this.size, other.size) + && Objects.deepEquals(this.width, other.width) + && Objects.deepEquals(this.height, other.height) + && Objects.deepEquals(this.duration, other.duration) + } + + override fun hashCode(): Int { + return arrayOf( + uri, + size, + width, + height, + duration + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/TrimAndCropOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/TrimAndCropOptions.kt index c1cdbd1..4bc62e6 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/TrimAndCropOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/TrimAndCropOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -41,6 +42,30 @@ data class TrimAndCropOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is TrimAndCropOptions) return false + return Objects.deepEquals(this.startTime, other.startTime) + && Objects.deepEquals(this.endTime, other.endTime) + && Objects.deepEquals(this.x, other.x) + && Objects.deepEquals(this.y, other.y) + && Objects.deepEquals(this.width, other.width) + && Objects.deepEquals(this.height, other.height) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + startTime, + endTime, + x, + y, + width, + height, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/TrimOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/TrimOptions.kt index 2a87bd0..3d914bd 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/TrimOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/TrimOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -29,6 +30,22 @@ data class TrimOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is TrimOptions) return false + return Objects.deepEquals(this.startTime, other.startTime) + && Objects.deepEquals(this.endTime, other.endTime) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + startTime, + endTime, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/VideoCropOptions.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/VideoCropOptions.kt index 0936008..39c97ee 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/VideoCropOptions.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/com/mediatoolkit/VideoCropOptions.kt @@ -9,6 +9,7 @@ package com.margelo.nitro.com.mediatoolkit import androidx.annotation.Keep import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects /** @@ -35,6 +36,26 @@ data class VideoCropOptions( ) { /* primary constructor */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is VideoCropOptions) return false + return Objects.deepEquals(this.x, other.x) + && Objects.deepEquals(this.y, other.y) + && Objects.deepEquals(this.width, other.width) + && Objects.deepEquals(this.height, other.height) + && Objects.deepEquals(this.outputPath, other.outputPath) + } + + override fun hashCode(): Int { + return arrayOf( + x, + y, + width, + height, + outputPath + ).contentDeepHashCode() + } + companion object { /** * Constructor called from C++ diff --git a/nitrogen/generated/ios/MediaToolkit+autolinking.rb b/nitrogen/generated/ios/MediaToolkit+autolinking.rb index 08e4e77..3aa4565 100644 --- a/nitrogen/generated/ios/MediaToolkit+autolinking.rb +++ b/nitrogen/generated/ios/MediaToolkit+autolinking.rb @@ -56,5 +56,7 @@ def add_nitrogen_files(spec) "SWIFT_OBJC_INTEROP_MODE" => "objcxx", # Enables stricter modular headers "DEFINES_MODULE" => "YES", + # Disable auto-generated ObjC header for Swift (Static linkage on Xcode 26.4 breaks here) + "SWIFT_INSTALL_OBJC_HEADER" => "NO", }) end diff --git a/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Bridge.cpp b/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Bridge.cpp index 2f44f1a..fcd2a51 100644 --- a/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Bridge.cpp +++ b/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Bridge.cpp @@ -30,6 +30,14 @@ namespace margelo::nitro::mediatoolkit::bridge::swift { }; } + // pragma MARK: std::function& /* result */)> + Func_void_std__vector_MediaResult_ create_Func_void_std__vector_MediaResult_(void* NON_NULL swiftClosureWrapper) noexcept { + auto swiftClosure = MediaToolkit::Func_void_std__vector_MediaResult_::fromUnsafe(swiftClosureWrapper); + return [swiftClosure = std::move(swiftClosure)](const std::vector& result) mutable -> void { + swiftClosure.call(result); + }; + } + // pragma MARK: std::function Func_void_ThumbnailResult create_Func_void_ThumbnailResult(void* NON_NULL swiftClosureWrapper) noexcept { auto swiftClosure = MediaToolkit::Func_void_ThumbnailResult::fromUnsafe(swiftClosureWrapper); diff --git a/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Bridge.hpp b/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Bridge.hpp index 3b4ea8b..df4e7ff 100644 --- a/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Bridge.hpp +++ b/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Bridge.hpp @@ -40,6 +40,7 @@ namespace MediaToolkit { class HybridMediaToolkitSpec_cxx; } #include #include #include +#include /** * Contains specialized versions of C++ templated types so they can be accessed from Swift, @@ -133,6 +134,51 @@ namespace margelo::nitro::mediatoolkit::bridge::swift { return optional.value(); } + // pragma MARK: std::vector + /** + * Specialized version of `std::vector`. + */ + using std__vector_MediaResult_ = std::vector; + inline std::vector create_std__vector_MediaResult_(size_t size) noexcept { + std::vector vector; + vector.reserve(size); + return vector; + } + + // pragma MARK: std::shared_ptr>> + /** + * Specialized version of `std::shared_ptr>>`. + */ + using std__shared_ptr_Promise_std__vector_MediaResult___ = std::shared_ptr>>; + inline std::shared_ptr>> create_std__shared_ptr_Promise_std__vector_MediaResult___() noexcept { + return Promise>::create(); + } + inline PromiseHolder> wrap_std__shared_ptr_Promise_std__vector_MediaResult___(std::shared_ptr>> promise) noexcept { + return PromiseHolder>(std::move(promise)); + } + + // pragma MARK: std::function& /* result */)> + /** + * Specialized version of `std::function&)>`. + */ + using Func_void_std__vector_MediaResult_ = std::function& /* result */)>; + /** + * Wrapper class for a `std::function& / * result * /)>`, this can be used from Swift. + */ + class Func_void_std__vector_MediaResult__Wrapper final { + public: + explicit Func_void_std__vector_MediaResult__Wrapper(std::function& /* result */)>&& func): _function(std::make_unique& /* result */)>>(std::move(func))) {} + inline void call(std::vector result) const noexcept { + _function->operator()(result); + } + private: + std::unique_ptr& /* result */)>> _function; + } SWIFT_NONCOPYABLE; + Func_void_std__vector_MediaResult_ create_Func_void_std__vector_MediaResult_(void* NON_NULL swiftClosureWrapper) noexcept; + inline Func_void_std__vector_MediaResult__Wrapper wrap_Func_void_std__vector_MediaResult_(Func_void_std__vector_MediaResult_ value) noexcept { + return Func_void_std__vector_MediaResult__Wrapper(std::move(value)); + } + // pragma MARK: std::shared_ptr> /** * Specialized version of `std::shared_ptr>`. @@ -267,6 +313,15 @@ namespace margelo::nitro::mediatoolkit::bridge::swift { return Result>>::withError(error); } + // pragma MARK: Result>>> + using Result_std__shared_ptr_Promise_std__vector_MediaResult____ = Result>>>; + inline Result_std__shared_ptr_Promise_std__vector_MediaResult____ create_Result_std__shared_ptr_Promise_std__vector_MediaResult____(const std::shared_ptr>>& value) noexcept { + return Result>>>::withValue(value); + } + inline Result_std__shared_ptr_Promise_std__vector_MediaResult____ create_Result_std__shared_ptr_Promise_std__vector_MediaResult____(const std::exception_ptr& error) noexcept { + return Result>>>::withError(error); + } + // pragma MARK: Result>> using Result_std__shared_ptr_Promise_ThumbnailResult___ = Result>>; inline Result_std__shared_ptr_Promise_ThumbnailResult___ create_Result_std__shared_ptr_Promise_ThumbnailResult___(const std::shared_ptr>& value) noexcept { diff --git a/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Umbrella.hpp b/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Umbrella.hpp index 4b369c6..8d9dee8 100644 --- a/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Umbrella.hpp +++ b/nitrogen/generated/ios/MediaToolkit-Swift-Cxx-Umbrella.hpp @@ -36,6 +36,8 @@ namespace margelo::nitro::mediatoolkit { struct ProcessVideoOptions; } namespace margelo::nitro::mediatoolkit { struct RotateOptions; } // Forward declaration of `SpeedOptions` to properly resolve imports. namespace margelo::nitro::mediatoolkit { struct SpeedOptions; } +// Forward declaration of `SplitImageOptions` to properly resolve imports. +namespace margelo::nitro::mediatoolkit { struct SplitImageOptions; } // Forward declaration of `ThumbnailOptions` to properly resolve imports. namespace margelo::nitro::mediatoolkit { struct ThumbnailOptions; } // Forward declaration of `ThumbnailResult` to properly resolve imports. @@ -62,6 +64,7 @@ namespace margelo::nitro::mediatoolkit { struct VideoCropOptions; } #include "ProcessVideoOptions.hpp" #include "RotateOptions.hpp" #include "SpeedOptions.hpp" +#include "SplitImageOptions.hpp" #include "ThumbnailOptions.hpp" #include "ThumbnailResult.hpp" #include "TrimAndCropOptions.hpp" @@ -73,6 +76,7 @@ namespace margelo::nitro::mediatoolkit { struct VideoCropOptions; } #include #include #include +#include // C++ helpers for Swift #include "MediaToolkit-Swift-Cxx-Bridge.hpp" diff --git a/nitrogen/generated/ios/c++/HybridMediaToolkitSpecSwift.hpp b/nitrogen/generated/ios/c++/HybridMediaToolkitSpecSwift.hpp index 4d39755..450fbae 100644 --- a/nitrogen/generated/ios/c++/HybridMediaToolkitSpecSwift.hpp +++ b/nitrogen/generated/ios/c++/HybridMediaToolkitSpecSwift.hpp @@ -18,6 +18,8 @@ namespace margelo::nitro::mediatoolkit { struct MediaResult; } namespace margelo::nitro::mediatoolkit { struct CropOptions; } // Forward declaration of `CompressImageOptions` to properly resolve imports. namespace margelo::nitro::mediatoolkit { struct CompressImageOptions; } +// Forward declaration of `SplitImageOptions` to properly resolve imports. +namespace margelo::nitro::mediatoolkit { struct SplitImageOptions; } // Forward declaration of `FlipOptions` to properly resolve imports. namespace margelo::nitro::mediatoolkit { struct FlipOptions; } // Forward declaration of `RotateOptions` to properly resolve imports. @@ -55,6 +57,8 @@ namespace margelo::nitro::mediatoolkit { struct LocationData; } #include "CropOptions.hpp" #include #include "CompressImageOptions.hpp" +#include +#include "SplitImageOptions.hpp" #include "FlipOptions.hpp" #include "RotateOptions.hpp" #include "VideoCropOptions.hpp" @@ -137,6 +141,14 @@ namespace margelo::nitro::mediatoolkit { auto __value = std::move(__result.value()); return __value; } + inline std::shared_ptr>> splitImage(const std::string& uri, const SplitImageOptions& options) override { + auto __result = _swiftPart.splitImage(uri, std::forward(options)); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } inline std::shared_ptr> flipImage(const std::string& uri, const FlipOptions& options) override { auto __result = _swiftPart.flipImage(uri, std::forward(options)); if (__result.hasError()) [[unlikely]] { diff --git a/nitrogen/generated/ios/swift/Func_void_std__vector_MediaResult_.swift b/nitrogen/generated/ios/swift/Func_void_std__vector_MediaResult_.swift new file mode 100644 index 0000000..10207df --- /dev/null +++ b/nitrogen/generated/ios/swift/Func_void_std__vector_MediaResult_.swift @@ -0,0 +1,46 @@ +/// +/// Func_void_std__vector_MediaResult_.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import NitroModules + +/** + * Wraps a Swift `(_ value: [MediaResult]) -> Void` as a class. + * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`. + */ +public final class Func_void_std__vector_MediaResult_ { + public typealias bridge = margelo.nitro.mediatoolkit.bridge.swift + + private let closure: (_ value: [MediaResult]) -> Void + + public init(_ closure: @escaping (_ value: [MediaResult]) -> Void) { + self.closure = closure + } + + @inline(__always) + public func call(value: bridge.std__vector_MediaResult_) -> Void { + self.closure(value.map({ __item in __item })) + } + + /** + * Casts this instance to a retained unsafe raw pointer. + * This acquires one additional strong reference on the object! + */ + @inline(__always) + public func toUnsafe() -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(self).toOpaque() + } + + /** + * Casts an unsafe pointer to a `Func_void_std__vector_MediaResult_`. + * The pointer has to be a retained opaque `Unmanaged`. + * This removes one strong reference from the object! + */ + @inline(__always) + public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_std__vector_MediaResult_ { + return Unmanaged.fromOpaque(pointer).takeRetainedValue() + } +} diff --git a/nitrogen/generated/ios/swift/HybridMediaToolkitSpec.swift b/nitrogen/generated/ios/swift/HybridMediaToolkitSpec.swift index 16eb2f1..a00cc8b 100644 --- a/nitrogen/generated/ios/swift/HybridMediaToolkitSpec.swift +++ b/nitrogen/generated/ios/swift/HybridMediaToolkitSpec.swift @@ -15,6 +15,7 @@ public protocol HybridMediaToolkitSpec_protocol: HybridObject { // Methods func cropImage(uri: String, options: CropOptions) throws -> Promise func compressImage(uri: String, options: CompressImageOptions) throws -> Promise + func splitImage(uri: String, options: SplitImageOptions) throws -> Promise<[MediaResult]> func flipImage(uri: String, options: FlipOptions) throws -> Promise func rotateImage(uri: String, options: RotateOptions) throws -> Promise func cropVideo(uri: String, options: VideoCropOptions) throws -> Promise diff --git a/nitrogen/generated/ios/swift/HybridMediaToolkitSpec_cxx.swift b/nitrogen/generated/ios/swift/HybridMediaToolkitSpec_cxx.swift index 4b18ba9..9024906 100644 --- a/nitrogen/generated/ios/swift/HybridMediaToolkitSpec_cxx.swift +++ b/nitrogen/generated/ios/swift/HybridMediaToolkitSpec_cxx.swift @@ -162,6 +162,31 @@ open class HybridMediaToolkitSpec_cxx { } } + @inline(__always) + public final func splitImage(uri: std.string, options: SplitImageOptions) -> bridge.Result_std__shared_ptr_Promise_std__vector_MediaResult____ { + do { + let __result = try self.__implementation.splitImage(uri: String(uri), options: options) + let __resultCpp = { () -> bridge.std__shared_ptr_Promise_std__vector_MediaResult___ in + let __promise = bridge.create_std__shared_ptr_Promise_std__vector_MediaResult___() + let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__vector_MediaResult___(__promise) + __result + .then({ __result in __promiseHolder.resolve({ () -> bridge.std__vector_MediaResult_ in + var __vector = bridge.create_std__vector_MediaResult_(__result.count) + for __item in __result { + __vector.push_back(__item) + } + return __vector + }()) }) + .catch({ __error in __promiseHolder.reject(__error.toCpp()) }) + return __promise + }() + return bridge.create_Result_std__shared_ptr_Promise_std__vector_MediaResult____(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_std__shared_ptr_Promise_std__vector_MediaResult____(__exceptionPtr) + } + } + @inline(__always) public final func flipImage(uri: std.string, options: FlipOptions) -> bridge.Result_std__shared_ptr_Promise_MediaResult___ { do { diff --git a/nitrogen/generated/ios/swift/SplitImageOptions.swift b/nitrogen/generated/ios/swift/SplitImageOptions.swift new file mode 100644 index 0000000..86aae8a --- /dev/null +++ b/nitrogen/generated/ios/swift/SplitImageOptions.swift @@ -0,0 +1,106 @@ +/// +/// SplitImageOptions.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import NitroModules + +/** + * Represents an instance of `SplitImageOptions`, backed by a C++ struct. + */ +public typealias SplitImageOptions = margelo.nitro.mediatoolkit.SplitImageOptions + +public extension SplitImageOptions { + private typealias bridge = margelo.nitro.mediatoolkit.bridge.swift + + /** + * Create a new instance of `SplitImageOptions`. + */ + init(rows: Double, columns: Double, format: String?, quality: Double?, outputDir: String?, prefix: String?) { + self.init(rows, columns, { () -> bridge.std__optional_std__string_ in + if let __unwrappedValue = format { + return bridge.create_std__optional_std__string_(std.string(__unwrappedValue)) + } else { + return .init() + } + }(), { () -> bridge.std__optional_double_ in + if let __unwrappedValue = quality { + return bridge.create_std__optional_double_(__unwrappedValue) + } else { + return .init() + } + }(), { () -> bridge.std__optional_std__string_ in + if let __unwrappedValue = outputDir { + return bridge.create_std__optional_std__string_(std.string(__unwrappedValue)) + } else { + return .init() + } + }(), { () -> bridge.std__optional_std__string_ in + if let __unwrappedValue = prefix { + return bridge.create_std__optional_std__string_(std.string(__unwrappedValue)) + } else { + return .init() + } + }()) + } + + @inline(__always) + var rows: Double { + return self.__rows + } + + @inline(__always) + var columns: Double { + return self.__columns + } + + @inline(__always) + var format: String? { + return { () -> String? in + if bridge.has_value_std__optional_std__string_(self.__format) { + let __unwrapped = bridge.get_std__optional_std__string_(self.__format) + return String(__unwrapped) + } else { + return nil + } + }() + } + + @inline(__always) + var quality: Double? { + return { () -> Double? in + if bridge.has_value_std__optional_double_(self.__quality) { + let __unwrapped = bridge.get_std__optional_double_(self.__quality) + return __unwrapped + } else { + return nil + } + }() + } + + @inline(__always) + var outputDir: String? { + return { () -> String? in + if bridge.has_value_std__optional_std__string_(self.__outputDir) { + let __unwrapped = bridge.get_std__optional_std__string_(self.__outputDir) + return String(__unwrapped) + } else { + return nil + } + }() + } + + @inline(__always) + var prefix: String? { + return { () -> String? in + if bridge.has_value_std__optional_std__string_(self.__prefix) { + let __unwrapped = bridge.get_std__optional_std__string_(self.__prefix) + return String(__unwrapped) + } else { + return nil + } + }() + } +} diff --git a/nitrogen/generated/shared/c++/HybridMediaToolkitSpec.cpp b/nitrogen/generated/shared/c++/HybridMediaToolkitSpec.cpp index 65c42f3..fbed800 100644 --- a/nitrogen/generated/shared/c++/HybridMediaToolkitSpec.cpp +++ b/nitrogen/generated/shared/c++/HybridMediaToolkitSpec.cpp @@ -16,6 +16,7 @@ namespace margelo::nitro::mediatoolkit { registerHybrids(this, [](Prototype& prototype) { prototype.registerHybridMethod("cropImage", &HybridMediaToolkitSpec::cropImage); prototype.registerHybridMethod("compressImage", &HybridMediaToolkitSpec::compressImage); + prototype.registerHybridMethod("splitImage", &HybridMediaToolkitSpec::splitImage); prototype.registerHybridMethod("flipImage", &HybridMediaToolkitSpec::flipImage); prototype.registerHybridMethod("rotateImage", &HybridMediaToolkitSpec::rotateImage); prototype.registerHybridMethod("cropVideo", &HybridMediaToolkitSpec::cropVideo); diff --git a/nitrogen/generated/shared/c++/HybridMediaToolkitSpec.hpp b/nitrogen/generated/shared/c++/HybridMediaToolkitSpec.hpp index b34716b..ceaa4b6 100644 --- a/nitrogen/generated/shared/c++/HybridMediaToolkitSpec.hpp +++ b/nitrogen/generated/shared/c++/HybridMediaToolkitSpec.hpp @@ -19,6 +19,8 @@ namespace margelo::nitro::mediatoolkit { struct MediaResult; } namespace margelo::nitro::mediatoolkit { struct CropOptions; } // Forward declaration of `CompressImageOptions` to properly resolve imports. namespace margelo::nitro::mediatoolkit { struct CompressImageOptions; } +// Forward declaration of `SplitImageOptions` to properly resolve imports. +namespace margelo::nitro::mediatoolkit { struct SplitImageOptions; } // Forward declaration of `FlipOptions` to properly resolve imports. namespace margelo::nitro::mediatoolkit { struct FlipOptions; } // Forward declaration of `RotateOptions` to properly resolve imports. @@ -53,6 +55,8 @@ namespace margelo::nitro::mediatoolkit { struct MediaMetadata; } #include #include "CropOptions.hpp" #include "CompressImageOptions.hpp" +#include +#include "SplitImageOptions.hpp" #include "FlipOptions.hpp" #include "RotateOptions.hpp" #include "VideoCropOptions.hpp" @@ -102,6 +106,7 @@ namespace margelo::nitro::mediatoolkit { // Methods virtual std::shared_ptr> cropImage(const std::string& uri, const CropOptions& options) = 0; virtual std::shared_ptr> compressImage(const std::string& uri, const CompressImageOptions& options) = 0; + virtual std::shared_ptr>> splitImage(const std::string& uri, const SplitImageOptions& options) = 0; virtual std::shared_ptr> flipImage(const std::string& uri, const FlipOptions& options) = 0; virtual std::shared_ptr> rotateImage(const std::string& uri, const RotateOptions& options) = 0; virtual std::shared_ptr> cropVideo(const std::string& uri, const VideoCropOptions& options) = 0; diff --git a/nitrogen/generated/shared/c++/SplitImageOptions.hpp b/nitrogen/generated/shared/c++/SplitImageOptions.hpp new file mode 100644 index 0000000..d84cbe2 --- /dev/null +++ b/nitrogen/generated/shared/c++/SplitImageOptions.hpp @@ -0,0 +1,104 @@ +/// +/// SplitImageOptions.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + + + +#include +#include + +namespace margelo::nitro::mediatoolkit { + + /** + * A struct which can be represented as a JavaScript object (SplitImageOptions). + */ + struct SplitImageOptions final { + public: + double rows SWIFT_PRIVATE; + double columns SWIFT_PRIVATE; + std::optional format SWIFT_PRIVATE; + std::optional quality SWIFT_PRIVATE; + std::optional outputDir SWIFT_PRIVATE; + std::optional prefix SWIFT_PRIVATE; + + public: + SplitImageOptions() = default; + explicit SplitImageOptions(double rows, double columns, std::optional format, std::optional quality, std::optional outputDir, std::optional prefix): rows(rows), columns(columns), format(format), quality(quality), outputDir(outputDir), prefix(prefix) {} + + public: + friend bool operator==(const SplitImageOptions& lhs, const SplitImageOptions& rhs) = default; + }; + +} // namespace margelo::nitro::mediatoolkit + +namespace margelo::nitro { + + // C++ SplitImageOptions <> JS SplitImageOptions (object) + template <> + struct JSIConverter final { + static inline margelo::nitro::mediatoolkit::SplitImageOptions fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + jsi::Object obj = arg.asObject(runtime); + return margelo::nitro::mediatoolkit::SplitImageOptions( + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "rows"))), + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "columns"))), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "format"))), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "quality"))), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "outputDir"))), + JSIConverter>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "prefix"))) + ); + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::mediatoolkit::SplitImageOptions& arg) { + jsi::Object obj(runtime); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "rows"), JSIConverter::toJSI(runtime, arg.rows)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "columns"), JSIConverter::toJSI(runtime, arg.columns)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "format"), JSIConverter>::toJSI(runtime, arg.format)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "quality"), JSIConverter>::toJSI(runtime, arg.quality)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "outputDir"), JSIConverter>::toJSI(runtime, arg.outputDir)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "prefix"), JSIConverter>::toJSI(runtime, arg.prefix)); + return obj; + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isObject()) { + return false; + } + jsi::Object obj = value.getObject(runtime); + if (!nitro::isPlainObject(runtime, obj)) { + return false; + } + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "rows")))) return false; + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "columns")))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "format")))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "quality")))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "outputDir")))) return false; + if (!JSIConverter>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "prefix")))) return false; + return true; + } + }; + +} // namespace margelo::nitro diff --git a/src/MediaToolkit.nitro.ts b/src/MediaToolkit.nitro.ts index 9f0f187..22d47cb 100644 --- a/src/MediaToolkit.nitro.ts +++ b/src/MediaToolkit.nitro.ts @@ -85,6 +85,21 @@ export interface CompressImageOptions { outputPath?: string; } +export interface SplitImageOptions { + /** Number of rows to split the image into */ + rows: number; + /** Number of columns to split the image into */ + columns: number; + /** Force output format: "jpeg" | "png" | "webp". Defaults to source format when supported. */ + format?: string; + /** Output quality 0–100 for lossy formats. Defaults to 100. */ + quality?: number; + /** Absolute output directory path (optional) */ + outputDir?: string; + /** Output filename prefix (optional) */ + prefix?: string; +} + export interface TrimOptions { /** Trim start in milliseconds */ startTime: number; @@ -236,6 +251,7 @@ export interface MediaToolkit uri: string, options: CompressImageOptions ): Promise; + splitImage(uri: string, options: SplitImageOptions): Promise; flipImage(uri: string, options: FlipOptions): Promise; rotateImage(uri: string, options: RotateOptions): Promise; diff --git a/src/index.ts b/src/index.ts index f00c9dc..79fe99e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ import type { MediaToolkit as MediaToolkitSpec } from './MediaToolkit.nitro'; export type { CropOptions, CompressImageOptions, + SplitImageOptions, TrimOptions, TrimAndCropOptions, VideoCropOptions, @@ -47,6 +48,11 @@ export const MediaToolkit = { */ compressImage: native.compressImage.bind(native), + /** + * Split an image into a rows x columns grid without resizing the source pixels. + */ + splitImage: native.splitImage.bind(native), + /** * Flip an image horizontally or vertically. */