├── example ├── .watchmanconfig ├── jest.config.js ├── .bundle │ └── config ├── app.json ├── tsconfig.json ├── babel.config.js ├── android │ ├── app │ │ ├── debug.keystore │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── values │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ └── drawable │ │ │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ ├── java │ │ │ │ │ └── com │ │ │ │ │ │ └── nitroexample │ │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ │ └── MainApplication.kt │ │ │ │ └── AndroidManifest.xml │ │ │ └── debug │ │ │ │ └── AndroidManifest.xml │ │ ├── proguard-rules.pro │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── settings.gradle │ ├── build.gradle │ ├── gradle.properties │ ├── gradlew.bat │ └── gradlew ├── ios │ ├── NitroExample │ │ ├── Images.xcassets │ │ │ ├── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── AppDelegate.h │ │ ├── main.m │ │ ├── AppDelegate.mm │ │ ├── PrivacyInfo.xcprivacy │ │ ├── Info.plist │ │ └── LaunchScreen.storyboard │ ├── NitroExample.xcworkspace │ │ └── contents.xcworkspacedata │ ├── .xcode.env │ ├── NitroExampleTests │ │ ├── Info.plist │ │ └── NitroExampleTests.m │ ├── Podfile │ └── NitroExample.xcodeproj │ │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── NitroExample.xcscheme │ │ └── project.pbxproj ├── index.js ├── Gemfile ├── __tests__ │ └── App.test.tsx ├── react-native.config.js ├── metro.config.js ├── biome.json ├── package.json ├── .gitignore ├── README.md ├── utils │ └── performance-benchmark.ts └── App.tsx ├── react-native-nitro-palette ├── .watchmanconfig ├── nitrogen │ └── generated │ │ ├── .gitattributes │ │ ├── ios │ │ ├── NitroPaletteAutolinking.swift │ │ ├── NitroPalette-Swift-Cxx-Bridge.cpp │ │ ├── NitroPalette-Swift-Cxx-Bridge.hpp │ │ ├── NitroPaletteAutolinking.mm │ │ ├── NitroPalette-Swift-Cxx-Umbrella.hpp │ │ └── NitroPalette+autolinking.rb │ │ ├── android │ │ ├── NitroPalette+autolinking.gradle │ │ ├── NitroPaletteOnLoad.hpp │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── margelo │ │ │ │ └── nitro │ │ │ │ └── nitropalette │ │ │ │ └── NitroPaletteOnLoad.kt │ │ ├── NitroPaletteOnLoad.cpp │ │ └── NitroPalette+autolinking.cmake │ │ └── shared │ │ └── c++ │ │ ├── HybridNitroPaletteSpec.cpp │ │ └── HybridNitroPaletteSpec.hpp ├── babel.config.js ├── android │ ├── src │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── cpp │ │ │ └── cpp-adapter.cpp │ │ │ └── java │ │ │ └── com │ │ │ └── nitropalette │ │ │ └── NitroPalettePackage.java │ ├── gradle.properties │ ├── CMakeLists.txt │ └── build.gradle ├── ios │ └── Bridge.h ├── src │ ├── specs │ │ ├── index.ts │ │ └── NitroPalette.nitro.ts │ ├── index.d.ts │ └── index.ts ├── nitro.json ├── cpp │ ├── NitroPalette.hpp │ ├── NitroPalette.cpp │ ├── MMCQ.hpp │ └── MMCQ.cpp ├── biome.json ├── .gitignore ├── tsconfig.json ├── NitroPalette.podspec ├── README.MD └── package.json ├── .gitignore ├── LICENSE.md ├── README.md └── package.json /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /react-native-nitro-palette/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-generated 2 | -------------------------------------------------------------------------------- /example/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NitroExample", 3 | "displayName": "NitroExample" 4 | } 5 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native/typescript-config/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /example/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/debug.keystore -------------------------------------------------------------------------------- /react-native-nitro-palette/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | } 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | NitroExample 3 | 4 | -------------------------------------------------------------------------------- /example/ios/NitroExample/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /react-native-nitro-palette/android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /example/ios/NitroExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : RCTAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /react-native-nitro-palette/ios/Bridge.h: -------------------------------------------------------------------------------- 1 | // 2 | // Bridge.h 3 | // nitro-palette 4 | // 5 | // Created by Ucekay on 12/7/2024 6 | // 7 | 8 | #pragma once 9 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ucekay/nitro-palette/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /react-native-nitro-palette/android/gradle.properties: -------------------------------------------------------------------------------- 1 | NitroPalette_kotlinVersion=2.0.21 2 | NitroPalette_minSdkVersion=23 3 | NitroPalette_targetSdkVersion=34 4 | NitroPalette_compileSdkVersion=34 5 | NitroPalette_ndkVersion=27.1.12297006 6 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import {AppRegistry} from 'react-native'; 6 | import App from './App'; 7 | import {name as appName} from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /react-native-nitro-palette/android/src/main/cpp/cpp-adapter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "NitroPaletteOnLoad.hpp" 3 | 4 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { 5 | return margelo::nitro::nitropalette::initialize(vm); 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/NitroExample/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /react-native-nitro-palette/src/specs/index.ts: -------------------------------------------------------------------------------- 1 | import { NitroModules } from "react-native-nitro-modules"; 2 | import type { NitroPalette as NitroPaletteSpec } from "./NitroPalette.nitro"; 3 | 4 | export const NitroPalette = 5 | NitroModules.createHybridObject("NitroPalette"); 6 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /example/ios/NitroExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/ios/NitroPaletteAutolinking.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPaletteAutolinking.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | public final class NitroPaletteAutolinking { 9 | public typealias bridge = margelo.nitro.nitropalette.bridge.swift 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /example/__tests__/App.test.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import 'react-native'; 6 | import React from 'react'; 7 | import App from '../App'; 8 | 9 | // Note: import explicitly to use the types shipped with jest. 10 | import {it} from '@jest/globals'; 11 | 12 | // Note: test renderer must be required after react-native. 13 | import renderer from 'react-test-renderer'; 14 | 15 | it('renders correctly', () => { 16 | renderer.create(); 17 | }); 18 | -------------------------------------------------------------------------------- /example/react-native.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pkg = require('../react-native-nitro-palette/package.json'); 3 | 4 | /** 5 | * @type {import('@react-native-community/cli-types').Config} 6 | */ 7 | module.exports = { 8 | dependencies: { 9 | [pkg.name]: { 10 | root: path.join(__dirname, '..', 'react-native-nitro-palette'), 11 | platforms: { 12 | android: { 13 | sourceDir: './android', 14 | }, 15 | }, 16 | }, 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitro.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://nitro.margelo.com/nitro.schema.json", 3 | "cxxNamespace": [ 4 | "nitropalette" 5 | ], 6 | "ios": { 7 | "iosModuleName": "NitroPalette" 8 | }, 9 | "android": { 10 | "androidNamespace": [ 11 | "nitropalette" 12 | ], 13 | "androidCxxLibName": "NitroPalette" 14 | }, 15 | "autolinking": { 16 | "NitroPalette": { 17 | "cpp": "NitroPalette" 18 | } 19 | }, 20 | "ignorePaths": [ 21 | "node_modules" 22 | ] 23 | } -------------------------------------------------------------------------------- /react-native-nitro-palette/src/specs/NitroPalette.nitro.ts: -------------------------------------------------------------------------------- 1 | import type { HybridObject } from "react-native-nitro-modules"; 2 | 3 | export interface NitroPalette 4 | extends HybridObject<{ ios: "c++"; android: "c++" }> { 5 | extractColors( 6 | source: ArrayBuffer, 7 | colorCount: number, 8 | quality: number, 9 | ignoreWhite: boolean, 10 | ): string[]; 11 | extractColorsAsync( 12 | source: ArrayBuffer, 13 | colorCount: number, 14 | quality: number, 15 | ignoreWhite: boolean, 16 | ): Promise; 17 | } 18 | -------------------------------------------------------------------------------- /example/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); 2 | const path = require('path'); 3 | const root = path.resolve(__dirname, '..'); 4 | 5 | /** 6 | * Metro configuration 7 | * https://facebook.github.io/metro/docs/configuration 8 | * 9 | * @type {import('metro-config').MetroConfig} 10 | */ 11 | const config = { 12 | watchFolders: [root], 13 | resolver: { 14 | unstable_enablePackageExports: true, 15 | }, 16 | }; 17 | 18 | module.exports = mergeConfig(getDefaultConfig(__dirname), config); 19 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/ios/NitroPalette-Swift-Cxx-Bridge.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPalette-Swift-Cxx-Bridge.cpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #include "NitroPalette-Swift-Cxx-Bridge.hpp" 9 | 10 | // Include C++ implementation defined types 11 | 12 | 13 | namespace margelo::nitro::nitropalette::bridge::swift { 14 | 15 | 16 | 17 | } // namespace margelo::nitro::nitropalette::bridge::swift 18 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> 4 | ex.autolinkLibrariesFromCommand() 5 | } 6 | rootProject.name = 'NitroExample' 7 | include ':app' 8 | includeBuild('../../node_modules/@react-native/gradle-plugin') 9 | 10 | include ':react-native-nitro-palette' 11 | project(':react-native-nitro-palette').projectDir = new File(rootProject.projectDir, '../../react-native-nitro-palette/android') 12 | -------------------------------------------------------------------------------- /example/biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 | "vcs": { 4 | "enabled": false, 5 | "clientKind": "git", 6 | "useIgnoreFile": false 7 | }, 8 | "files": { 9 | "ignoreUnknown": false, 10 | "ignore": [] 11 | }, 12 | "formatter": { 13 | "enabled": true, 14 | "indentStyle": "tab" 15 | }, 16 | "organizeImports": { 17 | "enabled": true 18 | }, 19 | "linter": { 20 | "enabled": true, 21 | "rules": { 22 | "recommended": true 23 | } 24 | }, 25 | "javascript": { 26 | "formatter": { 27 | "quoteStyle": "double" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /react-native-nitro-palette/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-native-nitro-palette" { 2 | /** 3 | * Extracts a color palette from an image 4 | * @param source - The image source (local file path, remote URL, or base64 data) 5 | * @param colorCount - The number of colors to extract 6 | * @param quality - The quality of the palette extraction (1 = best, 10 = fastest) 7 | * @param ignoreWhite - Whether to ignore white colors 8 | * @returns An array of colors in hex format 9 | */ 10 | export function getPaletteAsync( 11 | source: string, 12 | colorCount?: number, 13 | quality?: number, 14 | ignoreWhite?: boolean, 15 | ): string[]; 16 | } 17 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "35.0.0" 4 | minSdkVersion = 24 5 | compileSdkVersion = 35 6 | targetSdkVersion = 35 7 | ndkVersion = "27.1.12297006" 8 | kotlinVersion = "2.0.21" 9 | agpVersion = "8.8.2" 10 | } 11 | repositories { 12 | google() 13 | mavenCentral() 14 | } 15 | dependencies { 16 | classpath("com.android.tools.build:gradle:${agpVersion}") 17 | classpath("com.facebook.react:react-native-gradle-plugin") 18 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") 19 | } 20 | } 21 | 22 | apply plugin: "com.facebook.react.rootproject" 23 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/ios/NitroPalette-Swift-Cxx-Bridge.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPalette-Swift-Cxx-Bridge.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | // Forward declarations of C++ defined types 11 | 12 | 13 | // Forward declarations of Swift defined types 14 | 15 | 16 | // Include C++ defined types 17 | 18 | 19 | /** 20 | * Contains specialized versions of C++ templated types so they can be accessed from Swift, 21 | * as well as helper functions to interact with those C++ types from Swift. 22 | */ 23 | namespace margelo::nitro::nitropalette::bridge::swift { 24 | 25 | 26 | 27 | } // namespace margelo::nitro::nitropalette::bridge::swift 28 | -------------------------------------------------------------------------------- /example/ios/NitroExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/android/NitroPalette+autolinking.gradle: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPalette+autolinking.gradle 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | /// This is a Gradle file that adds all files generated by Nitrogen 9 | /// to the current Gradle project. 10 | /// 11 | /// To use it, add this to your build.gradle: 12 | /// ```gradle 13 | /// apply from: '../nitrogen/generated/android/NitroPalette+autolinking.gradle' 14 | /// ``` 15 | 16 | logger.warn("[NitroModules] 🔥 NitroPalette is boosted by nitro!") 17 | 18 | android { 19 | sourceSets { 20 | main { 21 | java.srcDirs += [ 22 | // Nitrogen files 23 | "${project.projectDir}/../nitrogen/generated/android/kotlin" 24 | ] 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/android/NitroPaletteOnLoad.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPaletteOnLoad.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #include 9 | #include 10 | 11 | namespace margelo::nitro::nitropalette { 12 | 13 | /** 14 | * Initializes the native (C++) part of NitroPalette, and autolinks all Hybrid Objects. 15 | * Call this in your `JNI_OnLoad` function (probably inside `cpp-adapter.cpp`). 16 | * Example: 17 | * ```cpp (cpp-adapter.cpp) 18 | * JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { 19 | * return margelo::nitro::nitropalette::initialize(vm); 20 | * } 21 | * ``` 22 | */ 23 | int initialize(JavaVM* vm); 24 | 25 | } // namespace margelo::nitro::nitropalette 26 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/shared/c++/HybridNitroPaletteSpec.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// HybridNitroPaletteSpec.cpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #include "HybridNitroPaletteSpec.hpp" 9 | 10 | namespace margelo::nitro::nitropalette { 11 | 12 | void HybridNitroPaletteSpec::loadHybridMethods() { 13 | // load base methods/properties 14 | HybridObject::loadHybridMethods(); 15 | // load custom methods/properties 16 | registerHybrids(this, [](Prototype& prototype) { 17 | prototype.registerHybridMethod("extractColors", &HybridNitroPaletteSpec::extractColors); 18 | prototype.registerHybridMethod("extractColorsAsync", &HybridNitroPaletteSpec::extractColorsAsync); 19 | }); 20 | } 21 | 22 | } // namespace margelo::nitro::nitropalette 23 | -------------------------------------------------------------------------------- /example/ios/NitroExample/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | 5 | @implementation AppDelegate 6 | 7 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 8 | { 9 | self.moduleName = @"NitroExample"; 10 | // You can add your custom initial props in the dictionary below. 11 | // They will be passed down to the ViewController used by React Native. 12 | self.initialProps = @{}; 13 | 14 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 15 | } 16 | 17 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 18 | { 19 | return [self bundleURL]; 20 | } 21 | 22 | - (NSURL *)bundleURL 23 | { 24 | #if DEBUG 25 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; 26 | #else 27 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 28 | #endif 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /react-native-nitro-palette/android/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9.0) 2 | 3 | project(NitroPalette) 4 | 5 | 6 | set (PACKAGE_NAME NitroPalette) 7 | set (CMAKE_VERBOSE_MAKEFILE ON) 8 | set (CMAKE_CXX_STANDARD 20) 9 | 10 | # Define C++ library and add all sources 11 | add_library(${PACKAGE_NAME} SHARED 12 | src/main/cpp/cpp-adapter.cpp 13 | ../cpp/NitroPalette.cpp 14 | ../cpp/MMCQ.cpp 15 | ../cpp/NitroPalette.hpp 16 | ../cpp/MMCQ.hpp 17 | ) 18 | 19 | # Add Nitrogen specs :) 20 | include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroPalette+autolinking.cmake) 21 | 22 | # Set up local includes 23 | include_directories( 24 | "src/main/cpp" 25 | "../cpp" 26 | ) 27 | 28 | find_library(LOG_LIB log) 29 | 30 | # Link all libraries together 31 | target_link_libraries( 32 | ${PACKAGE_NAME} 33 | ${LOG_LIB} 34 | android # <-- Android core 35 | ) 36 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/nitroexample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.nitroexample 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "NitroExample" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /react-native-nitro-palette/cpp/NitroPalette.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "HybridNitroPaletteSpec.hpp" 5 | 6 | namespace margelo { 7 | namespace nitro { 8 | namespace nitropalette { 9 | class NitroPalette : public HybridNitroPaletteSpec { 10 | public: 11 | NitroPalette() : HybridObject(TAG), HybridNitroPaletteSpec() {} 12 | 13 | std::vector extractColors( 14 | const std::shared_ptr& source, double colorCount, 15 | double quality, bool ignoreWhite) override; 16 | 17 | std::shared_ptr>> extractColorsAsync( 18 | const std::shared_ptr& source, double colorCount, 19 | double quality, bool ignoreWhite) override; 20 | 21 | size_t getExternalMemorySize() noexcept override { 22 | return sizeof(NitroPalette) + currentImageSize_; 23 | } 24 | 25 | private: 26 | size_t currentImageSize_ = 0; 27 | }; 28 | 29 | } // namespace nitropalette 30 | } // namespace nitro 31 | } // namespace margelo -------------------------------------------------------------------------------- /react-native-nitro-palette/android/src/main/java/com/nitropalette/NitroPalettePackage.java: -------------------------------------------------------------------------------- 1 | package com.nitropalette; 2 | 3 | import android.util.Log; 4 | import androidx.annotation.Nullable; 5 | import androidx.annotation.NonNull; 6 | 7 | import com.facebook.react.bridge.NativeModule; 8 | import com.facebook.react.bridge.ReactApplicationContext; 9 | import com.facebook.react.module.model.ReactModuleInfoProvider; 10 | import com.facebook.react.TurboReactPackage; 11 | import com.margelo.nitro.core.HybridObject; 12 | import com.margelo.nitro.nitropalette.NitroPaletteOnLoad; 13 | 14 | import java.util.HashMap; 15 | import java.util.function.Supplier; 16 | 17 | public class NitroPalettePackage extends TurboReactPackage { 18 | @Nullable 19 | @Override 20 | public NativeModule getModule(@NonNull String name, @NonNull ReactApplicationContext reactContext) { 21 | return null; 22 | } 23 | 24 | @NonNull 25 | @Override 26 | public ReactModuleInfoProvider getReactModuleInfoProvider() { 27 | return HashMap::new; 28 | } 29 | 30 | static { 31 | System.loadLibrary("NitroPalette"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /react-native-nitro-palette/biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/2.0.0-beta.1/schema.json", 3 | "vcs": { 4 | "enabled": false, 5 | "clientKind": "git", 6 | "useIgnoreFile": false 7 | }, 8 | "files": { 9 | "ignoreUnknown": false 10 | }, 11 | "formatter": { 12 | "enabled": true, 13 | "indentStyle": "tab" 14 | }, 15 | "linter": { 16 | "enabled": true, 17 | "rules": { 18 | "recommended": true 19 | } 20 | }, 21 | "javascript": { 22 | "formatter": { 23 | "quoteStyle": "double" 24 | } 25 | }, 26 | "assist": { 27 | "enabled": true, 28 | "actions": { 29 | "source": { 30 | "organizeImports": { 31 | "level": "on", 32 | "options": { 33 | "groups": [ 34 | ":URL:", 35 | ":BLANK_LINE:", 36 | ":NODE:", 37 | ":BLANK_LINE:", 38 | ["react", "react-native"], 39 | ":BLANK_LINE:", 40 | ["expo-*", "expo"], 41 | ":BLANK_LINE:", 42 | ":PACKAGE:", 43 | ":BLANK_LINE:", 44 | ":ALIAS:", 45 | ":BLANK_LINE:", 46 | ":PATH:" 47 | ] 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IJ 33 | # 34 | .classpath 35 | .cxx 36 | .gradle 37 | .idea 38 | .project 39 | .settings 40 | local.properties 41 | android.iml 42 | 43 | # Cocoapods 44 | # 45 | example/ios/Pods 46 | 47 | # Ruby 48 | example/vendor/ 49 | 50 | # node.js 51 | # 52 | node_modules/ 53 | npm-debug.log 54 | yarn-debug.log 55 | yarn-error.log 56 | 57 | # BUCK 58 | buck-out/ 59 | \.buckd/ 60 | android/app/libs 61 | android/keystores/debug.keystore 62 | 63 | # Yarn 64 | .yarn/* 65 | !.yarn/patches 66 | !.yarn/plugins 67 | !.yarn/releases 68 | !.yarn/sdks 69 | !.yarn/versions 70 | 71 | # Expo 72 | .expo/ 73 | 74 | # Turborepo 75 | .turbo/ 76 | 77 | # generated by bob 78 | lib/ 79 | 80 | *.tsbuildinfo 81 | 82 | *.env -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Kimura Yusuke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/ios/NitroExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /react-native-nitro-palette/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IJ 33 | # 34 | .classpath 35 | .cxx 36 | .gradle 37 | .idea 38 | .project 39 | .settings 40 | local.properties 41 | android.iml 42 | 43 | # Cocoapods 44 | # 45 | example/ios/Pods 46 | 47 | # Ruby 48 | example/vendor/ 49 | 50 | # node.js 51 | # 52 | node_modules/ 53 | npm-debug.log 54 | yarn-debug.log 55 | yarn-error.log 56 | 57 | # BUCK 58 | buck-out/ 59 | \.buckd/ 60 | android/app/libs 61 | android/keystores/debug.keystore 62 | 63 | # Yarn 64 | .yarn/* 65 | !.yarn/patches 66 | !.yarn/plugins 67 | !.yarn/releases 68 | !.yarn/sdks 69 | !.yarn/versions 70 | 71 | # Expo 72 | .expo/ 73 | 74 | # Turborepo 75 | .turbo/ 76 | 77 | # generated by bob 78 | lib/ 79 | 80 | *.tsbuildinfo -------------------------------------------------------------------------------- /react-native-nitro-palette/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "rootDir": ".", 5 | "allowUnreachableCode": false, 6 | "allowUnusedLabels": false, 7 | "esModuleInterop": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "jsx": "react", 10 | "lib": [ 11 | "esnext" 12 | ], 13 | "module": "esnext", 14 | "moduleResolution": "node", 15 | "noEmit": false, 16 | "noFallthroughCasesInSwitch": true, 17 | "noImplicitReturns": true, 18 | "noImplicitUseStrict": false, 19 | "noStrictGenericChecks": false, 20 | "noUncheckedIndexedAccess": true, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "resolveJsonModule": true, 24 | "skipLibCheck": true, 25 | "strict": true, 26 | "target": "esnext", 27 | "verbatimModuleSyntax": true 28 | }, 29 | "exclude": [ 30 | "**/node_modules", 31 | "**/lib", 32 | "**/.eslintrc.js", 33 | "**/.prettierrc.js", 34 | "**/jest.config.js", 35 | "**/babel.config.js", 36 | "**/metro.config.js", 37 | "**/tsconfig.json" 38 | ], 39 | "include": [ 40 | "src" 41 | ] 42 | } -------------------------------------------------------------------------------- /example/ios/NitroExample/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | CA92.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyCollectedDataTypes 33 | 34 | NSPrivacyTracking 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/ios/NitroPaletteAutolinking.mm: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPaletteAutolinking.mm 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #import 9 | #import 10 | 11 | #import 12 | 13 | #include "NitroPalette.hpp" 14 | 15 | @interface NitroPaletteAutolinking : NSObject 16 | @end 17 | 18 | @implementation NitroPaletteAutolinking 19 | 20 | + (void) load { 21 | using namespace margelo::nitro; 22 | using namespace margelo::nitro::nitropalette; 23 | 24 | HybridObjectRegistry::registerHybridObjectConstructor( 25 | "NitroPalette", 26 | []() -> std::shared_ptr { 27 | static_assert(std::is_default_constructible_v, 28 | "The HybridObject \"NitroPalette\" is not default-constructible! " 29 | "Create a public constructor that takes zero arguments to be able to autolink this HybridObject."); 30 | return std::make_shared(); 31 | } 32 | ); 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /react-native-nitro-palette/NitroPalette.podspec: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = "NitroPalette" 7 | s.version = package["version"] 8 | s.summary = package["description"] 9 | s.homepage = package["homepage"] 10 | s.license = package["license"] 11 | s.authors = package["author"] 12 | 13 | s.platforms = { :ios => min_ios_version_supported, :visionos => 1.0 } 14 | s.source = { :git => "https://github.com/ucekay/react-native-nitro-palette.git", :tag => "#{s.version}" } 15 | 16 | s.source_files = [ 17 | # Implementation (Swift) 18 | "ios/**/*.{swift}", 19 | # Autolinking/Registration (Objective-C++) 20 | "ios/**/*.{m,mm}", 21 | # Implementation (C++ objects) 22 | "cpp/**/*.{hpp,cpp}", 23 | ] 24 | 25 | s.pod_target_xcconfig = { 26 | # C++ compiler flags, mainly for folly. 27 | "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) FOLLY_NO_CONFIG FOLLY_CFG_NO_COROUTINES" 28 | } 29 | 30 | load 'nitrogen/generated/ios/NitroPalette+autolinking.rb' 31 | add_nitrogen_files(s) 32 | 33 | s.dependency 'React-jsi' 34 | s.dependency 'React-callinvoker' 35 | install_modules_dependencies(s) 36 | end 37 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'NitroExample' do 18 | config = use_native_modules! 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | target 'NitroExampleTests' do 27 | inherit! :complete 28 | # Pods for testing 29 | end 30 | 31 | post_install do |installer| 32 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 33 | react_native_post_install( 34 | installer, 35 | config[:reactNativePath], 36 | :mac_catalyst_enabled => false, 37 | # :ccache_enabled => true 38 | ) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/android/kotlin/com/margelo/nitro/nitropalette/NitroPaletteOnLoad.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPaletteOnLoad.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.nitropalette 9 | 10 | import android.util.Log 11 | 12 | internal class NitroPaletteOnLoad { 13 | companion object { 14 | private const val TAG = "NitroPaletteOnLoad" 15 | private var didLoad = false 16 | /** 17 | * Initializes the native part of "NitroPalette". 18 | * This method is idempotent and can be called more than once. 19 | */ 20 | @JvmStatic 21 | fun initializeNative() { 22 | if (didLoad) return 23 | try { 24 | Log.i(TAG, "Loading NitroPalette C++ library...") 25 | System.loadLibrary("NitroPalette") 26 | Log.i(TAG, "Successfully loaded NitroPalette C++ library!") 27 | didLoad = true 28 | } catch (e: Error) { 29 | Log.e(TAG, "Failed to load NitroPalette C++ library! Is it properly installed and linked? " + 30 | "Is the name correct? (see `CMakeLists.txt`, at `add_library(...)`)", e) 31 | throw e 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nitro-example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios --simulator='iPhone 16'", 8 | "lint": "eslint .", 9 | "start": "react-native start --reset-cache", 10 | "test": "jest", 11 | "pod": "pod install --project-directory=ios" 12 | }, 13 | "dependencies": { 14 | "@shopify/react-native-skia": "^1.12.4", 15 | "react": "19.0.0", 16 | "react-native": "0.79.1", 17 | "react-native-color-thief": "^0.3.4", 18 | "react-native-nitro-modules": "^0.25.2" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.26.10", 22 | "@babel/preset-env": "^7.26.9", 23 | "@babel/runtime": "^7.27.0", 24 | "@biomejs/biome": "^1.9.4", 25 | "@react-native-community/cli": "18.0.0", 26 | "@react-native-community/cli-platform-android": "18.0.0", 27 | "@react-native-community/cli-platform-ios": "18.0.0", 28 | "@react-native/babel-preset": "0.79.1", 29 | "@react-native/metro-config": "0.79.1", 30 | "@react-native/typescript-config": "0.79.1", 31 | "@types/react": "^19.1.2", 32 | "@types/react-test-renderer": "^19.1.0", 33 | "babel-jest": "^29.7.0", 34 | "jest": "^29.7.0", 35 | "react-test-renderer": "19.1.0", 36 | "typescript": "5.8.3" 37 | }, 38 | "engines": { 39 | "node": ">=18" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | *.keystore 35 | !debug.keystore 36 | 37 | # node.js 38 | # 39 | node_modules/ 40 | npm-debug.log 41 | yarn-error.log 42 | 43 | # fastlane 44 | # 45 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 46 | # screenshots whenever they are needed. 47 | # For more information about the recommended setup visit: 48 | # https://docs.fastlane.tools/best-practices/source-control/ 49 | 50 | **/fastlane/report.xml 51 | **/fastlane/Preview.html 52 | **/fastlane/screenshots 53 | **/fastlane/test_output 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | 58 | # Ruby / CocoaPods 59 | **/Pods/ 60 | /vendor/bundle/ 61 | 62 | # Temporary files created by Metro to check the health of the file watcher 63 | .metro-health-check* 64 | 65 | # testing 66 | /coverage 67 | 68 | # Yarn 69 | .yarn/* 70 | !.yarn/patches 71 | !.yarn/plugins 72 | !.yarn/releases 73 | !.yarn/sdks 74 | !.yarn/versions 75 | -------------------------------------------------------------------------------- /react-native-nitro-palette/src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AlphaType, 3 | ColorType, 4 | type DataSourceParam, 5 | type SkImage, 6 | Skia, 7 | loadData, 8 | } from "@shopify/react-native-skia"; 9 | import { NitroPalette } from "./specs"; 10 | 11 | const imgFactory = Skia.Image.MakeImageFromEncoded.bind(Skia.Image); 12 | 13 | export const getPaletteAsync = async ( 14 | source: DataSourceParam | string, 15 | colorCount = 5, 16 | quality = 10, 17 | ignoreWhite = true, 18 | ): Promise => { 19 | try { 20 | let image: SkImage | null = null; 21 | if (typeof source === "string" && source.startsWith("file://")) { 22 | const imageData = await Skia.Data.fromURI(source); 23 | image = Skia.Image.MakeImageFromEncoded(imageData); 24 | } else { 25 | image = await loadData(source, imgFactory); 26 | } 27 | if (!image) { 28 | throw new Error("Failed to create image"); 29 | } 30 | const pixels = image.readPixels(0, 0, { 31 | width: image.width(), 32 | height: image.height(), 33 | colorType: ColorType.RGBA_8888, 34 | alphaType: AlphaType.Unpremul, 35 | }); 36 | if (!pixels) { 37 | throw new Error("Failed to read pixels"); 38 | } 39 | return NitroPalette.extractColorsAsync( 40 | pixels.buffer as ArrayBuffer, 41 | colorCount, 42 | quality, 43 | ignoreWhite, 44 | ); 45 | } catch (error) { 46 | throw new Error(error instanceof Error ? error.message : String(error)); 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/ios/NitroPalette-Swift-Cxx-Umbrella.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPalette-Swift-Cxx-Umbrella.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | // Forward declarations of C++ defined types 11 | 12 | 13 | // Include C++ defined types 14 | 15 | 16 | // C++ helpers for Swift 17 | #include "NitroPalette-Swift-Cxx-Bridge.hpp" 18 | 19 | // Common C++ types used in Swift 20 | #include 21 | #include 22 | #include 23 | 24 | // Forward declarations of Swift defined types 25 | 26 | 27 | // Include Swift defined types 28 | #if __has_include("NitroPalette-Swift.h") 29 | // This header is generated by Xcode/Swift on every app build. 30 | // If it cannot be found, make sure the Swift module's name (= podspec name) is actually "NitroPalette". 31 | #include "NitroPalette-Swift.h" 32 | // Same as above, but used when building with frameworks (`use_frameworks`) 33 | #elif __has_include() 34 | #include 35 | #else 36 | #error NitroPalette's autogenerated Swift header cannot be found! Make sure the Swift module's name (= podspec name) is actually "NitroPalette", and try building the app first. 37 | #endif 38 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/android/NitroPaletteOnLoad.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPaletteOnLoad.cpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #ifndef BUILDING_NITROPALETTE_WITH_GENERATED_CMAKE_PROJECT 9 | #error NitroPaletteOnLoad.cpp is not being built with the autogenerated CMakeLists.txt project. Is a different CMakeLists.txt building this? 10 | #endif 11 | 12 | #include "NitroPaletteOnLoad.hpp" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "NitroPalette.hpp" 19 | 20 | namespace margelo::nitro::nitropalette { 21 | 22 | int initialize(JavaVM* vm) { 23 | using namespace margelo::nitro; 24 | using namespace margelo::nitro::nitropalette; 25 | using namespace facebook; 26 | 27 | return facebook::jni::initialize(vm, [] { 28 | // Register native JNI methods 29 | 30 | 31 | // Register Nitro Hybrid Objects 32 | HybridObjectRegistry::registerHybridObjectConstructor( 33 | "NitroPalette", 34 | []() -> std::shared_ptr { 35 | static_assert(std::is_default_constructible_v, 36 | "The HybridObject \"NitroPalette\" is not default-constructible! " 37 | "Create a public constructor that takes zero arguments to be able to autolink this HybridObject."); 38 | return std::make_shared(); 39 | } 40 | ); 41 | }); 42 | } 43 | 44 | } // namespace margelo::nitro::nitropalette 45 | -------------------------------------------------------------------------------- /example/ios/NitroExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | NitroExample 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | 30 | NSAllowsArbitraryLoads 31 | 32 | NSAllowsLocalNetworking 33 | 34 | 35 | NSLocationWhenInUseUsageDescription 36 | 37 | UILaunchStoryboardName 38 | LaunchScreen 39 | UIRequiredDeviceCapabilities 40 | 41 | arm64 42 | 43 | UISupportedInterfaceOrientations 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | UIViewControllerBasedStatusBarAppearance 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/nitroexample/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.nitroexample 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeHost 8 | import com.facebook.react.ReactPackage 9 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | import com.facebook.react.soloader.OpenSourceMergedSoMapping 13 | import com.facebook.soloader.SoLoader 14 | 15 | class MainApplication : Application(), ReactApplication { 16 | 17 | override val reactNativeHost: ReactNativeHost = 18 | object : DefaultReactNativeHost(this) { 19 | override fun getPackages(): List = 20 | PackageList(this).packages.apply { 21 | // Packages that cannot be autolinked yet can be added manually here, for example: 22 | // add(MyReactNativePackage()) 23 | } 24 | 25 | override fun getJSMainModuleName(): String = "index" 26 | 27 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 28 | 29 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 30 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 31 | } 32 | 33 | override val reactHost: ReactHost 34 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 35 | 36 | override fun onCreate() { 37 | super.onCreate() 38 | SoLoader.init(this, OpenSourceMergedSoMapping) 39 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 40 | // If you opted-in for the New Architecture, we load the native entry point for this app. 41 | load() 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-nitro-palette 2 | 3 | A color palette package for React Native/Expo that extracts dominant colors from images. 4 | 5 | ## Features 6 | - High-performance color extraction powered by C++ implementation using Nitro Modules 7 | - Support for both local and remote images 8 | - Customizable number of colors to extract 9 | - Adjustable quality settings for performance optimization 10 | - Option to filter out white/transparent colors 11 | - Full TypeScript support 12 | 13 | ## Demo 14 | 15 | ### Remote Image Color Extraction 16 | https://github.com/user-attachments/assets/78b2f760-7345-423a-9eaa-1d3558baafe3 17 | 18 | ### Device Library Image Color Extraction 19 | 20 | ## Usage 21 | 22 | For detailed implementation examples and usage instructions, please see the README.md in the react-native-nitro-palette directory. 23 | 24 | ### Basic Usage Example 25 | 26 | ```javascript 27 | import { getPaletteAsync } from 'react-native-nitro-palette'; 28 | 29 | const colors = await getPaletteAsync( 30 | 'https://example.jpg', 31 | 5, // number of colors to extract (default: 5) 32 | 10, // quality (1 = best, 10 = fastest, default: 10) 33 | true // ignore white colors (default: true) 34 | ); 35 | 36 | console.log(colors); // ['rgb(255,0,0)', 'rgb(0,255,0)', ...] 37 | ``` 38 | 39 | ## Running Example App 40 | 41 | The example application demonstrates the full capabilities of react-native-nitro-palette. 42 | 43 | > **Note**: Currently, the example app is only configured to run on iOS. However, the react-native-nitro-palette package itself is fully compatible with both iOS and Android platforms. 44 | 45 | ### To run the example: 46 | 47 | 1. Clone this repository 48 | 2. Navigate to the example directory: `cd example` 49 | 3. Install dependencies: `npm install` or `yarn install` 50 | 4. For iOS: 51 | - Install pods: `cd ios && pod install` 52 | - Run: `npm run ios` or `yarn ios` 53 | 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-nitro-palette", 3 | "private": true, 4 | "version": "1.1.2", 5 | "repository": "https://github.com/ucekay/react-native-nitro-palette.git", 6 | "author": "Ucekay", 7 | "scripts": { 8 | "bootstrap": "bun --filter=\"**\" install && bun tsc && bun --filter=\"example\" pods", 9 | "typescript": "bun --filter=\"**\" typescript", 10 | "release": "release-it" 11 | }, 12 | "workspaces": [ 13 | "react-native-nitro-palette", 14 | "example" 15 | ], 16 | "devDependencies": { 17 | "@jamesacarr/eslint-formatter-github-actions": "^0.2.0", 18 | "@release-it/bumper": "^6.0.1", 19 | "@release-it/conventional-changelog": "^8.0.1", 20 | "release-it": "^17.6.0" 21 | }, 22 | "release-it": { 23 | "npm": { 24 | "publish": false 25 | }, 26 | "git": { 27 | "commitMessage": "chore: release ${version}", 28 | "tagName": "v${version}", 29 | "requireCleanWorkingDir": false 30 | }, 31 | "github": { 32 | "release": true 33 | }, 34 | "plugins": { 35 | "@release-it/conventional-changelog": { 36 | "preset": { 37 | "name": "conventionalcommits", 38 | "types": [ 39 | { 40 | "type": "feat", 41 | "section": "✨ Features" 42 | }, 43 | { 44 | "type": "perf", 45 | "section": "💨 Performance Improvements" 46 | }, 47 | { 48 | "type": "fix", 49 | "section": "🐛 Bug Fixes" 50 | }, 51 | { 52 | "type": "chore(deps)", 53 | "section": "🛠️ Dependency Upgrades" 54 | }, 55 | { 56 | "type": "docs", 57 | "section": "📚 Documentation" 58 | } 59 | ] 60 | } 61 | } 62 | } 63 | }, 64 | "dependencies": { 65 | "eslint-config-prettier": "^9.1.0", 66 | "eslint-plugin-prettier": "^5.2.1", 67 | "prettier": "^3.4.1" 68 | }, 69 | "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" 70 | } 71 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | android.enableJetifier=true 25 | 26 | # Use this property to specify which architecture you want to build. 27 | # You can also override it from the CLI using 28 | # ./gradlew -PreactNativeArchitectures=x86_64 29 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 30 | 31 | # Use this property to enable support to the new architecture. 32 | # This will allow you to use TurboModules and the Fabric render in 33 | # your application. You should enable this flag either if you want 34 | # to write custom TurboModules/Fabric components OR use libraries that 35 | # are providing them. 36 | newArchEnabled=true 37 | 38 | # Use this property to enable or disable the Hermes JS engine. 39 | # If set to false, you will be using JSC instead. 40 | hermesEnabled=true 41 | 42 | # 依存関係解決の問題を解決するための追加設定 43 | android.nonTransitiveRClass=true 44 | org.gradle.configureondemand=true 45 | org.gradle.caching=true -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 22 | 23 | 24 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/ios/NitroPalette+autolinking.rb: -------------------------------------------------------------------------------- 1 | # 2 | # NitroPalette+autolinking.rb 3 | # This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | # https://github.com/mrousavy/nitro 5 | # Copyright © 2025 Marc Rousavy @ Margelo 6 | # 7 | 8 | # This is a Ruby script that adds all files generated by Nitrogen 9 | # to the given podspec. 10 | # 11 | # To use it, add this to your .podspec: 12 | # ```ruby 13 | # Pod::Spec.new do |spec| 14 | # # ... 15 | # 16 | # # Add all files generated by Nitrogen 17 | # load 'nitrogen/generated/ios/NitroPalette+autolinking.rb' 18 | # add_nitrogen_files(spec) 19 | # end 20 | # ``` 21 | 22 | def add_nitrogen_files(spec) 23 | Pod::UI.puts "[NitroModules] 🔥 NitroPalette is boosted by nitro!" 24 | 25 | spec.dependency "NitroModules" 26 | 27 | current_source_files = Array(spec.attributes_hash['source_files']) 28 | spec.source_files = current_source_files + [ 29 | # Generated cross-platform specs 30 | "nitrogen/generated/shared/**/*.{h,hpp,c,cpp,swift}", 31 | # Generated bridges for the cross-platform specs 32 | "nitrogen/generated/ios/**/*.{h,hpp,c,cpp,mm,swift}", 33 | ] 34 | 35 | current_public_header_files = Array(spec.attributes_hash['public_header_files']) 36 | spec.public_header_files = current_public_header_files + [ 37 | # Generated specs 38 | "nitrogen/generated/shared/**/*.{h,hpp}", 39 | # Swift to C++ bridging helpers 40 | "nitrogen/generated/ios/NitroPalette-Swift-Cxx-Bridge.hpp" 41 | ] 42 | 43 | current_private_header_files = Array(spec.attributes_hash['private_header_files']) 44 | spec.private_header_files = current_private_header_files + [ 45 | # iOS specific specs 46 | "nitrogen/generated/ios/c++/**/*.{h,hpp}", 47 | # Views are framework-specific and should be private 48 | "nitrogen/generated/shared/**/views/**/*" 49 | ] 50 | 51 | current_pod_target_xcconfig = spec.attributes_hash['pod_target_xcconfig'] || {} 52 | spec.pod_target_xcconfig = current_pod_target_xcconfig.merge({ 53 | # Use C++ 20 54 | "CLANG_CXX_LANGUAGE_STANDARD" => "c++20", 55 | # Enables C++ <-> Swift interop (by default it's only C) 56 | "SWIFT_OBJC_INTEROP_MODE" => "objcxx", 57 | # Enables stricter modular headers 58 | "DEFINES_MODULE" => "YES", 59 | }) 60 | end 61 | -------------------------------------------------------------------------------- /example/ios/NitroExampleTests/NitroExampleTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #define TIMEOUT_SECONDS 600 8 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 9 | 10 | @interface NitroExampleTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation NitroExampleTests 15 | 16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test 17 | { 18 | if (test(view)) { 19 | return YES; 20 | } 21 | for (UIView *subview in [view subviews]) { 22 | if ([self findSubviewInView:subview matching:test]) { 23 | return YES; 24 | } 25 | } 26 | return NO; 27 | } 28 | 29 | - (void)testRendersWelcomeScreen 30 | { 31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 33 | BOOL foundElement = NO; 34 | 35 | __block NSString *redboxError = nil; 36 | #ifdef DEBUG 37 | RCTSetLogFunction( 38 | ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 39 | if (level >= RCTLogLevelError) { 40 | redboxError = message; 41 | } 42 | }); 43 | #endif 44 | 45 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 46 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 47 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 48 | 49 | foundElement = [self findSubviewInView:vc.view 50 | matching:^BOOL(UIView *view) { 51 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 52 | return YES; 53 | } 54 | return NO; 55 | }]; 56 | } 57 | 58 | #ifdef DEBUG 59 | RCTSetLogFunction(RCTDefaultLogFunction); 60 | #endif 61 | 62 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 63 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/shared/c++/HybridNitroPaletteSpec.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// HybridNitroPaletteSpec.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #if __has_include() 11 | #include 12 | #else 13 | #error NitroModules cannot be found! Are you sure you installed NitroModules properly? 14 | #endif 15 | 16 | // Forward declaration of `ArrayBuffer` to properly resolve imports. 17 | namespace NitroModules { class ArrayBuffer; } 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace margelo::nitro::nitropalette { 25 | 26 | using namespace margelo::nitro; 27 | 28 | /** 29 | * An abstract base class for `NitroPalette` 30 | * Inherit this class to create instances of `HybridNitroPaletteSpec` in C++. 31 | * You must explicitly call `HybridObject`'s constructor yourself, because it is virtual. 32 | * @example 33 | * ```cpp 34 | * class HybridNitroPalette: public HybridNitroPaletteSpec { 35 | * public: 36 | * HybridNitroPalette(...): HybridObject(TAG) { ... } 37 | * // ... 38 | * }; 39 | * ``` 40 | */ 41 | class HybridNitroPaletteSpec: public virtual HybridObject { 42 | public: 43 | // Constructor 44 | explicit HybridNitroPaletteSpec(): HybridObject(TAG) { } 45 | 46 | // Destructor 47 | ~HybridNitroPaletteSpec() override = default; 48 | 49 | public: 50 | // Properties 51 | 52 | 53 | public: 54 | // Methods 55 | virtual std::vector extractColors(const std::shared_ptr& source, double colorCount, double quality, bool ignoreWhite) = 0; 56 | virtual std::shared_ptr>> extractColorsAsync(const std::shared_ptr& source, double colorCount, double quality, bool ignoreWhite) = 0; 57 | 58 | protected: 59 | // Hybrid Setup 60 | void loadHybridMethods() override; 61 | 62 | protected: 63 | // Tag for logging 64 | static constexpr auto TAG = "NitroPalette"; 65 | }; 66 | 67 | } // namespace margelo::nitro::nitropalette 68 | -------------------------------------------------------------------------------- /react-native-nitro-palette/README.MD: -------------------------------------------------------------------------------- 1 | # react-native-nitro-palette 2 | 3 | A fast and efficient color palette extraction library for React Native, powered by C++ and the MMCQ (Modified Median Cut Quantization) algorithm. 4 | 5 | ## Features 6 | 7 | - 🚀 High-performance color extraction using native C++ 8 | - 🎨 Extracts dominant colors from images 9 | - 🔧 Configurable color count and quality settings 10 | 11 | ## Installation 12 | 13 | ```sh 14 | npm install react-native-nitro-palette react-native-nitro-modules react-native-skia 15 | # or 16 | yarn add react-native-nitro-palette react-native-nitro-modules react-native-skia 17 | ``` 18 | 19 | ### Additional Setup 20 | 21 | #### For Expo projects 22 | ```sh 23 | yarn expo prebuild --clean 24 | ``` 25 | 26 | #### For React Native projects 27 | ```sh 28 | cd ios && pod install 29 | ``` 30 | 31 | ## Usage 32 | 33 | ```typescript 34 | import { getPaletteAsync } from 'react-native-nitro-palette'; 35 | 36 | // Extract colors from a remote URL 37 | const colors1 = await getPaletteAsync( 38 | 'https://example.jpg', 39 | 5, // number of colors to extract (default: 5) 40 | 10, // quality (1 = best, 10 = fastest, default: 10) 41 | true // ignore white colors (default: true) 42 | ); 43 | 44 | // Extract colors from a JS Bundle 45 | const colors2 = await getPaletteAsync( 46 | require('./assets/logo.jpg'), 47 | 5, 48 | 10, 49 | true 50 | ) 51 | 52 | // Extract colors from a local image uri 53 | const colors3 = await getPaletteAsync( 54 | 'file://...', 55 | 5, 56 | 10, 57 | true 58 | ) 59 | 60 | console.log(colors1); // ['rgb(255,0,0)', 'rgb(0,255,0)', ...] 61 | ``` 62 | 63 | ## API Reference 64 | 65 | ### getPaletteAsync(source, colorCount?, quality?, ignoreWhite?) 66 | 67 | Extract colors from an image source. 68 | 69 | #### Parameters 70 | 71 | - `source` (string) - The image source (local file path, remote URL, or base64 data) 72 | - `colorCount` (number) - Optional. Number of colors to extract (default: 5) 73 | - `quality` (number) - Optional. Quality of color extraction (1 = best, 10 = fastest, default: 10) 74 | - `ignoreWhite` (boolean) - Optional. Whether to ignore white colors (default: true) 75 | 76 | #### Returns 77 | 78 | - `Promise` - Array of RGB colors in CSS format (e.g., 'rgb(255,0,0)') 79 | 80 | ## License 81 | 82 | MIT 83 | 84 | ## Credits 85 | 86 | This library is a C++ port of [ColorThiefSwift](https://github.com/yamoridon/ColorThiefSwift), which is a Swift implementation of ColorThief. The MMCQ (Modified Median Cut Quantization) algorithm implementation is based on the original work. 87 | 88 | ### Related Projects 89 | - [ColorThiefSwift](https://github.com/yamoridon/ColorThiefSwift) 90 | - [Color Thief](https://lokeshdhakar.com/projects/color-thief/) -------------------------------------------------------------------------------- /react-native-nitro-palette/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-nitro-palette", 3 | "version": "1.1.2", 4 | "description": "Nitro module package", 5 | "main": "./lib/commonjs/index.js", 6 | "module": "./lib/module/index.js", 7 | "types": "./lib/typescript/src/index.d.ts", 8 | "react-native": "src/index", 9 | "source": "src/index", 10 | "files": [ 11 | "src", 12 | "react-native.config.js", 13 | "lib", 14 | "nitrogen", 15 | "android/build.gradle", 16 | "android/gradle.properties", 17 | "android/CMakeLists.txt", 18 | "android/src", 19 | "cpp/MMCQ.cpp", 20 | "cpp/MMCQ.hpp", 21 | "cpp/NitroPalette.cpp", 22 | "cpp/NitroPalette.hpp", 23 | "ios/**/*.h", 24 | "ios/**/*.m", 25 | "ios/**/*.mm", 26 | "ios/**/*.cpp", 27 | "ios/**/*.swift", 28 | "app.plugin.js", 29 | "*.podspec", 30 | "README.md" 31 | ], 32 | "scripts": { 33 | "postinstall": "bun build || exit 0;", 34 | "build": "rm -rf lib && bun typecheck && bob build", 35 | "typecheck": "tsc --noEmit", 36 | "clean": "rm -rf android/build node_modules/**/android/build lib android/.cxx node_modules/**/android/.cxx", 37 | "release": "release-it", 38 | "codegen": "bun typecheck && nitro-codegen --logLevel=\"debug\"", 39 | "postcodegen": "bun run build" 40 | }, 41 | "keywords": [ 42 | "react-native" 43 | ], 44 | "repository": "https://github.com/ucekay/react-native-nitro-palette.git", 45 | "author": "Ucekay", 46 | "license": "MIT", 47 | "bugs": "https://github.com/ucekay/react-native-nitro-palette/issues", 48 | "homepage": "https://github.com/ucekay/react-native-nitro-palette#readme", 49 | "publishConfig": { 50 | "registry": "https://registry.npmjs.org/", 51 | "access": "public" 52 | }, 53 | "devDependencies": { 54 | "@biomejs/biome": "^1.9.4", 55 | "@shopify/react-native-skia": "^1.12.4", 56 | "@types/jest": "^29.5.14", 57 | "@types/react": "^19.1.2", 58 | "nitro-codegen": "^0.25.2", 59 | "react": "19.0.0", 60 | "react-native": "^0.79.1", 61 | "react-native-builder-bob": "^0.40.6", 62 | "react-native-nitro-modules": "^0.25.2", 63 | "release-it": "^19.0.1", 64 | "typescript": "^5.8.3" 65 | }, 66 | "peerDependencies": { 67 | "react": "*", 68 | "react-native": "*", 69 | "react-native-nitro-modules": "*", 70 | "@shopify/react-native-skia": "*" 71 | }, 72 | "release-it": { 73 | "npm": { 74 | "publish": true 75 | }, 76 | "git": false, 77 | "github": { 78 | "release": false 79 | }, 80 | "hooks": { 81 | "before:init": "bun typecheck", 82 | "after:bump": "bun run build" 83 | } 84 | }, 85 | "react-native-builder-bob": { 86 | "source": "src", 87 | "output": "lib", 88 | "targets": [ 89 | "commonjs", 90 | "module", 91 | [ 92 | "typescript", 93 | { 94 | "project": "tsconfig.json" 95 | } 96 | ] 97 | ] 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /react-native-nitro-palette/nitrogen/generated/android/NitroPalette+autolinking.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # NitroPalette+autolinking.cmake 3 | # This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | # https://github.com/mrousavy/nitro 5 | # Copyright © 2025 Marc Rousavy @ Margelo 6 | # 7 | 8 | # This is a CMake file that adds all files generated by Nitrogen 9 | # to the current CMake project. 10 | # 11 | # To use it, add this to your CMakeLists.txt: 12 | # ```cmake 13 | # include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroPalette+autolinking.cmake) 14 | # ``` 15 | 16 | # Add all headers that were generated by Nitrogen 17 | include_directories( 18 | "../nitrogen/generated/shared/c++" 19 | "../nitrogen/generated/android/c++" 20 | "../nitrogen/generated/android/" 21 | ) 22 | 23 | # Add all .cpp sources that were generated by Nitrogen 24 | target_sources( 25 | # CMake project name (Android C++ library name) 26 | NitroPalette PRIVATE 27 | # Autolinking Setup 28 | ../nitrogen/generated/android/NitroPaletteOnLoad.cpp 29 | # Shared Nitrogen C++ sources 30 | ../nitrogen/generated/shared/c++/HybridNitroPaletteSpec.cpp 31 | # Android-specific Nitrogen C++ sources 32 | 33 | ) 34 | 35 | # Define a flag to check if we are building properly 36 | add_definitions(-DBUILDING_NITROPALETTE_WITH_GENERATED_CMAKE_PROJECT) 37 | 38 | # From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake 39 | # Used in node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake 40 | target_compile_definitions( 41 | NitroPalette PRIVATE 42 | -DFOLLY_NO_CONFIG=1 43 | -DFOLLY_HAVE_CLOCK_GETTIME=1 44 | -DFOLLY_USE_LIBCPP=1 45 | -DFOLLY_CFG_NO_COROUTINES=1 46 | -DFOLLY_MOBILE=1 47 | -DFOLLY_HAVE_RECVMMSG=1 48 | -DFOLLY_HAVE_PTHREAD=1 49 | # Once we target android-23 above, we can comment 50 | # the following line. NDK uses GNU style stderror_r() after API 23. 51 | -DFOLLY_HAVE_XSI_STRERROR_R=1 52 | ) 53 | 54 | # Add all libraries required by the generated specs 55 | find_package(fbjni REQUIRED) # <-- Used for communication between Java <-> C++ 56 | find_package(ReactAndroid REQUIRED) # <-- Used to set up React Native bindings (e.g. CallInvoker/TurboModule) 57 | find_package(react-native-nitro-modules REQUIRED) # <-- Used to create all HybridObjects and use the Nitro core library 58 | 59 | # Link all libraries together 60 | target_link_libraries( 61 | NitroPalette 62 | fbjni::fbjni # <-- Facebook C++ JNI helpers 63 | ReactAndroid::jsi # <-- RN: JSI 64 | react-native-nitro-modules::NitroModules # <-- NitroModules Core :) 65 | ) 66 | 67 | # Link react-native (different prefab between RN 0.75 and RN 0.76) 68 | if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76) 69 | target_link_libraries( 70 | NitroPalette 71 | ReactAndroid::reactnative # <-- RN: Native Modules umbrella prefab 72 | ) 73 | else() 74 | target_link_libraries( 75 | NitroPalette 76 | ReactAndroid::react_nativemodule_core # <-- RN: TurboModules Core 77 | ) 78 | endif() 79 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /react-native-nitro-palette/cpp/NitroPalette.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "NitroPalette.hpp" 3 | #include "MMCQ.hpp" 4 | 5 | #include 6 | #include 7 | 8 | namespace margelo { 9 | namespace nitro { 10 | namespace nitropalette { 11 | 12 | std::vector NitroPalette::extractColors( 13 | const std::shared_ptr& source, double colorCount, 14 | double quality, bool ignoreWhite) { 15 | currentImageSize_ = source->size(); 16 | 17 | if (!source || currentImageSize_ < 4 || currentImageSize_ % 4 != 0) { 18 | throw std::runtime_error("Invalid source buffer size or format"); 19 | } 20 | 21 | colorCount = std::clamp(colorCount, 1.0, 20.0); 22 | quality = std::clamp(quality, 1.0, 10.0); 23 | const int colorCountInt = static_cast(colorCount); 24 | 25 | auto pixels = source->data(); 26 | std::vector pixelsVector(pixels, pixels + currentImageSize_); 27 | 28 | auto colorMap = MMCQ::quantize(pixelsVector, colorCountInt, 29 | static_cast(quality), ignoreWhite); 30 | 31 | auto palette = colorMap->makePalette(); 32 | 33 | if (palette.empty()) { 34 | return {}; 35 | } 36 | 37 | std::vector result; 38 | result.reserve(palette.size()); 39 | for (const auto& color : palette) { 40 | result.push_back(color.toString()); 41 | } 42 | 43 | return result; 44 | } 45 | 46 | std::shared_ptr>> 47 | NitroPalette::extractColorsAsync(const std::shared_ptr& source, 48 | double colorCount, double quality, 49 | bool ignoreWhite) { 50 | if (!source) { 51 | throw std::runtime_error("Source buffer is null"); 52 | } 53 | 54 | uint8_t* sourceData = source->data(); 55 | size_t sourceSize = source->size(); 56 | 57 | if (sourceData == nullptr) { 58 | throw std::runtime_error("Invalid source buffer data"); 59 | } 60 | 61 | std::vector sourceCopy(sourceData, sourceData + sourceSize); 62 | 63 | return Promise>::async( 64 | [this, sourceCopy = std::move(sourceCopy), colorCount, quality, 65 | ignoreWhite]() { 66 | currentImageSize_ = sourceCopy.size(); 67 | 68 | if (sourceCopy.empty() || currentImageSize_ < 4 || 69 | currentImageSize_ % 4 != 0) { 70 | throw std::runtime_error("Invalid source buffer size or format"); 71 | } 72 | 73 | const double clampedColorCount = std::clamp(colorCount, 1.0, 20.0); 74 | const double clampedQuality = std::clamp(quality, 1.0, 10.0); 75 | const int colorCountInt = static_cast(clampedColorCount); 76 | 77 | auto colorMap = 78 | MMCQ::quantize(sourceCopy, colorCountInt, 79 | static_cast(clampedQuality), ignoreWhite); 80 | 81 | auto palette = colorMap->makePalette(); 82 | 83 | if (palette.empty()) { 84 | return std::vector(); 85 | } 86 | 87 | std::vector result; 88 | result.reserve(palette.size()); 89 | for (const auto& color : palette) { 90 | result.push_back(color.toString()); 91 | } 92 | 93 | return result; 94 | }); 95 | } 96 | } // namespace nitropalette 97 | } // namespace nitro 98 | } // namespace margelo -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). 2 | 3 | # Getting Started 4 | 5 | >**Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. 6 | 7 | ## Step 1: Start the Metro Server 8 | 9 | First, you will need to start **Metro**, the JavaScript _bundler_ that ships _with_ React Native. 10 | 11 | To start Metro, run the following command from the _root_ of your React Native project: 12 | 13 | ```bash 14 | # using npm 15 | npm start 16 | 17 | # OR using Yarn 18 | yarn start 19 | ``` 20 | 21 | ## Step 2: Start your Application 22 | 23 | Let Metro Bundler run in its _own_ terminal. Open a _new_ terminal from the _root_ of your React Native project. Run the following command to start your _Android_ or _iOS_ app: 24 | 25 | ### For Android 26 | 27 | ```bash 28 | # using npm 29 | npm run android 30 | 31 | # OR using Yarn 32 | yarn android 33 | ``` 34 | 35 | ### For iOS 36 | 37 | ```bash 38 | # using npm 39 | npm run ios 40 | 41 | # OR using Yarn 42 | yarn ios 43 | ``` 44 | 45 | If everything is set up _correctly_, you should see your new app running in your _Android Emulator_ or _iOS Simulator_ shortly provided you have set up your emulator/simulator correctly. 46 | 47 | This is one way to run your app — you can also run it directly from within Android Studio and Xcode respectively. 48 | 49 | ## Step 3: Modifying your App 50 | 51 | Now that you have successfully run the app, let's modify it. 52 | 53 | 1. Open `App.tsx` in your text editor of choice and edit some lines. 54 | 2. For **Android**: Press the R key twice or select **"Reload"** from the **Developer Menu** (Ctrl + M (on Window and Linux) or Cmd ⌘ + M (on macOS)) to see your changes! 55 | 56 | For **iOS**: Hit Cmd ⌘ + R in your iOS Simulator to reload the app and see your changes! 57 | 58 | ## Congratulations! :tada: 59 | 60 | You've successfully run and modified your React Native App. :partying_face: 61 | 62 | ### Now what? 63 | 64 | - If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps). 65 | - If you're curious to learn more about React Native, check out the [Introduction to React Native](https://reactnative.dev/docs/getting-started). 66 | 67 | # Troubleshooting 68 | 69 | If you can't get this to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page. 70 | 71 | # Learn More 72 | 73 | To learn more about React Native, take a look at the following resources: 74 | 75 | - [React Native Website](https://reactnative.dev) - learn more about React Native. 76 | - [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment. 77 | - [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**. 78 | - [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts. 79 | - [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native. 80 | -------------------------------------------------------------------------------- /react-native-nitro-palette/cpp/MMCQ.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMCQ_HPP 2 | #define MMCQ_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class MMCQ { 10 | public: 11 | struct Color { 12 | uint8_t r; 13 | uint8_t g; 14 | uint8_t b; 15 | 16 | Color() : r(0), g(0), b(0) {} 17 | Color(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {} 18 | 19 | std::string toString() const; 20 | }; 21 | 22 | enum ColorChannel { R, G, B }; 23 | 24 | class VBox { 25 | public: 26 | struct Range { 27 | int begin; 28 | int end; 29 | }; 30 | 31 | VBox(uint8_t rMin, uint8_t rMax, uint8_t gMin, uint8_t gMax, uint8_t bMin, 32 | uint8_t bMax, std::vector& histogram); 33 | VBox(const VBox& vbox); 34 | VBox& operator=(const VBox& other); 35 | VBox& operator=(VBox&& other) noexcept = default; 36 | 37 | int getVolume(bool forceRecalculation = false) const; 38 | int getCount(bool forceRecalculation = false) const; 39 | Color getAverage(bool forceRecalculation = false) const; 40 | ColorChannel widestColorChannel() const; 41 | 42 | uint8_t rMin, rMax; 43 | uint8_t gMin, gMax; 44 | uint8_t bMin, bMax; 45 | 46 | private: 47 | std::shared_ptr> histogram; 48 | mutable std::optional average; 49 | mutable std::optional volume; 50 | mutable std::optional count; 51 | }; 52 | 53 | class ColorMap { 54 | public: 55 | ColorMap() = default; 56 | ColorMap(const ColorMap& other); 57 | ColorMap& operator=(const ColorMap& other); 58 | ColorMap(ColorMap&& other) noexcept = default; 59 | ColorMap& operator=(ColorMap&& other) noexcept = default; 60 | std::vector makePalette() const; 61 | Color makeNearestColor(const Color& color) const; 62 | void push(const VBox& vbox); 63 | 64 | private: 65 | std::vector vboxes; 66 | }; 67 | 68 | static std::unique_ptr quantize(const std::vector& pixels, 69 | int maxColors, int quality, 70 | bool ignoreWhite); 71 | 72 | private: 73 | static constexpr int SIGNAL_BITS = 5; 74 | static constexpr int RIGHT_SHIFT = 8 - SIGNAL_BITS; 75 | static constexpr int MULTIPLIER = 1 << RIGHT_SHIFT; 76 | static constexpr int HISTOGRAM_SIZE = 1 << (3 * SIGNAL_BITS); 77 | static constexpr int VBOX_LENGTH = 1 << SIGNAL_BITS; 78 | static constexpr double FRACTION_BY_POPULATION = 0.75; 79 | static constexpr int MAX_ITERATIONS = 1000; 80 | 81 | static int makeColorIndexOf(int red, int green, int blue); 82 | 83 | static std::pair>, VBox> 84 | makeHistogramAndBox( 85 | const std::vector>& pixels, int quality, 86 | bool ignoreWhite); 87 | 88 | static std::vector> applyMedianCut( 89 | const std::vector>& histogram, const VBox& vbox); 90 | 91 | static std::vector cut(ColorChannel axis, const VBox& vbox, int vboxMin, 92 | int vboxMax, const std::vector& partialSun, 93 | const std::vector& lookAheadSum, int total); 94 | 95 | static void iterate(std::vector& queue, 96 | bool (*comparator)(const VBox&, const VBox&), int target, 97 | const std::vector& histogram); 98 | 99 | static bool compareByCount(const VBox& a, const VBox& b); 100 | static bool compareByProduct(const VBox& a, const VBox& b); 101 | }; 102 | 103 | #endif -------------------------------------------------------------------------------- /example/ios/NitroExample.xcodeproj/xcshareddata/xcschemes/NitroExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /example/ios/NitroExample/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/utils/performance-benchmark.ts: -------------------------------------------------------------------------------- 1 | // src/utils/types.ts 2 | export type BenchmarkResult = { 3 | operationName: string; 4 | executionTime: number; 5 | iterations: number; 6 | averageTime: number; 7 | minTime: number; 8 | maxTime: number; 9 | errors: number; // エラー回数を追加 10 | }; 11 | 12 | export interface IBenchmarkUtil { 13 | measure( 14 | operationName: string, 15 | operation: () => T | Promise, 16 | iterations?: number, 17 | ): Promise; 18 | getResults(operationName?: string): BenchmarkResult[]; 19 | clearResults(operationName?: string): void; 20 | } 21 | 22 | // エラー型の定義 23 | export class BenchmarkError extends Error { 24 | constructor( 25 | message: string, 26 | public readonly originalError?: unknown, 27 | ) { 28 | super(message); 29 | this.name = "BenchmarkError"; 30 | } 31 | } 32 | export class BenchmarkUtil implements IBenchmarkUtil { 33 | private static instance: BenchmarkUtil; 34 | private results: Map = new Map(); 35 | 36 | private constructor() {} 37 | 38 | static getInstance(): BenchmarkUtil { 39 | if (!BenchmarkUtil.instance) { 40 | BenchmarkUtil.instance = new BenchmarkUtil(); 41 | } 42 | return BenchmarkUtil.instance; 43 | } 44 | 45 | private async executeOperation( 46 | operation: () => T | Promise, 47 | ): Promise<{ executionTime: number; error?: Error }> { 48 | const startTime = performance.now(); 49 | 50 | try { 51 | await Promise.resolve(operation()); 52 | const endTime = performance.now(); 53 | return { executionTime: endTime - startTime }; 54 | } catch (error) { 55 | const endTime = performance.now(); 56 | return { 57 | executionTime: endTime - startTime, 58 | error: error instanceof Error ? error : new Error(String(error)), 59 | }; 60 | } 61 | } 62 | 63 | async measure( 64 | operationName: string, 65 | operation: () => T | Promise, 66 | iterations = 1, 67 | ): Promise { 68 | if (iterations < 1) { 69 | throw new BenchmarkError("Iterations must be greater than 0"); 70 | } 71 | 72 | const times: number[] = []; 73 | let errorCount = 0; 74 | 75 | try { 76 | for (let i = 0; i < iterations; i++) { 77 | const { executionTime, error } = await this.executeOperation(operation); 78 | 79 | if (error) { 80 | errorCount++; 81 | console.error(`Error in iteration ${i + 1}:`, error); 82 | } 83 | 84 | times.push(executionTime); 85 | } 86 | 87 | const existingTimes = this.results.get(operationName) || []; 88 | this.results.set(operationName, [...existingTimes, ...times]); 89 | 90 | const totalTime = times.reduce((acc, time) => acc + time, 0); 91 | const averageTime = totalTime / iterations; 92 | const minTime = Math.min(...times); 93 | const maxTime = Math.max(...times); 94 | 95 | return { 96 | operationName, 97 | executionTime: totalTime, 98 | iterations, 99 | averageTime, 100 | minTime, 101 | maxTime, 102 | errors: errorCount, 103 | }; 104 | } catch (error) { 105 | throw new BenchmarkError( 106 | `Failed to complete benchmark for ${operationName}`, 107 | error, 108 | ); 109 | } 110 | } 111 | 112 | getResults(operationName?: string): BenchmarkResult[] { 113 | if (operationName) { 114 | const times = this.results.get(operationName); 115 | if (!times) return []; 116 | 117 | const totalTime = times.reduce((acc, time) => acc + time, 0); 118 | return [ 119 | { 120 | operationName, 121 | executionTime: totalTime, 122 | iterations: times.length, 123 | averageTime: totalTime / times.length, 124 | minTime: Math.min(...times), 125 | maxTime: Math.max(...times), 126 | errors: 0, 127 | }, 128 | ]; 129 | } 130 | 131 | return Array.from(this.results.entries()).map(([name, times]) => { 132 | const totalTime = times.reduce((acc, time) => acc + time, 0); 133 | return { 134 | operationName: name, 135 | executionTime: totalTime, 136 | iterations: times.length, 137 | averageTime: totalTime / times.length, 138 | minTime: Math.min(...times), 139 | maxTime: Math.max(...times), 140 | errors: 0, 141 | }; 142 | }); 143 | } 144 | 145 | clearResults(operationName?: string): void { 146 | if (operationName) { 147 | this.results.delete(operationName); 148 | } else { 149 | this.results.clear(); 150 | } 151 | } 152 | } 153 | 154 | // シングルトンインスタンスをエクスポート 155 | export const benchmark = BenchmarkUtil.getInstance(); 156 | -------------------------------------------------------------------------------- /react-native-nitro-palette/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath "com.android.tools.build:gradle:8.8.2" 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21" 10 | } 11 | } 12 | 13 | def reactNativeArchitectures() { 14 | def value = rootProject.getProperties().get("reactNativeArchitectures") 15 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] 16 | } 17 | 18 | def isNewArchitectureEnabled() { 19 | return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" 20 | } 21 | 22 | apply plugin: "com.android.library" 23 | apply plugin: 'org.jetbrains.kotlin.android' 24 | apply from: '../nitrogen/generated/android/NitroPalette+autolinking.gradle' 25 | 26 | if (isNewArchitectureEnabled()) { 27 | apply plugin: "com.facebook.react" 28 | } 29 | 30 | def getExtOrDefault(name) { 31 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["NitroPalette_" + name] 32 | } 33 | 34 | def getExtOrIntegerDefault(name) { 35 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["NitroPalette_" + name]).toInteger() 36 | } 37 | 38 | android { 39 | namespace "com.nitropalette" 40 | 41 | ndkVersion getExtOrDefault("ndkVersion") 42 | compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") 43 | 44 | defaultConfig { 45 | minSdkVersion getExtOrIntegerDefault("minSdkVersion") 46 | targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") 47 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() 48 | 49 | externalNativeBuild { 50 | cmake { 51 | cppFlags "-frtti -fexceptions -Wall -Wextra -fstack-protector-all" 52 | arguments "-DANDROID_STL=c++_shared" 53 | abiFilters (*reactNativeArchitectures()) 54 | 55 | buildTypes { 56 | debug { 57 | cppFlags "-O1 -g" 58 | } 59 | release { 60 | cppFlags "-O2" 61 | } 62 | } 63 | } 64 | } 65 | } 66 | 67 | externalNativeBuild { 68 | cmake { 69 | path "CMakeLists.txt" 70 | } 71 | } 72 | 73 | packagingOptions { 74 | excludes = [ 75 | "META-INF", 76 | "META-INF/**", 77 | "**/libc++_shared.so", 78 | "**/libfbjni.so", 79 | "**/libjsi.so", 80 | "**/libfolly_json.so", 81 | "**/libfolly_runtime.so", 82 | "**/libglog.so", 83 | "**/libhermes.so", 84 | "**/libhermes-executor-debug.so", 85 | "**/libhermes_executor.so", 86 | "**/libreactnative.so", 87 | "**/libreactnativejni.so", 88 | "**/libturbomodulejsijni.so", 89 | "**/libreact_nativemodule_core.so", 90 | "**/libjscexecutor.so" 91 | ] 92 | } 93 | 94 | buildFeatures { 95 | buildConfig true 96 | prefab true 97 | } 98 | 99 | buildTypes { 100 | debug { 101 | minifyEnabled false 102 | } 103 | release { 104 | minifyEnabled false 105 | } 106 | } 107 | 108 | lintOptions { 109 | disable "GradleCompatible" 110 | } 111 | 112 | compileOptions { 113 | sourceCompatibility JavaVersion.VERSION_17 114 | targetCompatibility JavaVersion.VERSION_17 115 | } 116 | 117 | kotlinOptions { 118 | jvmTarget = "17" 119 | } 120 | 121 | sourceSets { 122 | main { 123 | if (isNewArchitectureEnabled()) { 124 | java.srcDirs += [ 125 | // React Codegen files 126 | "${project.buildDir}/generated/source/codegen/java" 127 | ] 128 | } 129 | } 130 | } 131 | } 132 | 133 | configurations { 134 | implementation { 135 | canBeResolved = true 136 | canBeConsumed = true 137 | } 138 | api { 139 | canBeResolved = true 140 | canBeConsumed = true 141 | } 142 | } 143 | 144 | repositories { 145 | mavenCentral() 146 | google() 147 | } 148 | 149 | dependencies { 150 | // For < 0.71, this will be from the local maven repo 151 | // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin 152 | //noinspection GradleDynamicVersion 153 | implementation "com.facebook.react:react-native:+" 154 | 155 | // Add a dependency on NitroModules 156 | implementation project(":react-native-nitro-modules") 157 | } 158 | 159 | if (isNewArchitectureEnabled()) { 160 | react { 161 | jsRootDir = file("../src/") 162 | libraryName = "NitroPalette" 163 | codegenJavaPackageName = "com.nitropalette" 164 | } 165 | } -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | apply plugin: "org.jetbrains.kotlin.android" 3 | apply plugin: "com.facebook.react" 4 | 5 | /** 6 | * This is the configuration block to customize your React Native Android app. 7 | * By default you don't need to apply any configuration, just uncomment the lines you need. 8 | */ 9 | react { 10 | /* Folders */ 11 | // The root of your project, i.e. where "package.json" lives. Default is '..' 12 | // root = file("../") 13 | // The folder where the react-native NPM package is. Default is ../node_modules/react-native 14 | reactNativeDir = file("../../../node_modules/react-native") 15 | // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen 16 | codegenDir = file("../../../node_modules/@react-native/codegen") 17 | // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js 18 | cliFile = file("../../../node_modules/react-native/cli.js") 19 | 20 | /* Variants */ 21 | // The list of variants to that are debuggable. For those we're going to 22 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'. 23 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. 24 | // debuggableVariants = ["liteDebug", "prodDebug"] 25 | 26 | /* Bundling */ 27 | // A list containing the node command and its flags. Default is just 'node'. 28 | // nodeExecutableAndArgs = ["node"] 29 | // 30 | // The command to run when bundling. By default is 'bundle' 31 | // bundleCommand = "ram-bundle" 32 | // 33 | // The path to the CLI configuration file. Default is empty. 34 | // bundleConfig = file(../rn-cli.config.js) 35 | // 36 | // The name of the generated asset file containing your JS bundle 37 | // bundleAssetName = "MyApplication.android.bundle" 38 | // 39 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' 40 | // entryFile = file("../js/MyApplication.android.js") 41 | // 42 | // A list of extra flags to pass to the 'bundle' commands. 43 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle 44 | // extraPackagerArgs = [] 45 | 46 | /* Hermes Commands */ 47 | // The hermes compiler command to run. By default it is 'hermesc' 48 | hermesCommand = "$rootDir/../../node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc" 49 | // 50 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" 51 | // hermesFlags = ["-O", "-output-source-map"] 52 | 53 | /* Autolinking */ 54 | autolinkLibrariesWithApp() 55 | } 56 | 57 | /** 58 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode. 59 | */ 60 | def enableProguardInReleaseBuilds = false 61 | 62 | /** 63 | * The preferred build flavor of JavaScriptCore (JSC) 64 | * 65 | * For example, to use the international variant, you can use: 66 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 67 | * 68 | * The international variant includes ICU i18n library and necessary data 69 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 70 | * give correct results when using with locales other than en-US. Note that 71 | * this variant is about 6MiB larger per architecture than default. 72 | */ 73 | def jscFlavor = 'org.webkit:android-jsc:+' 74 | 75 | android { 76 | ndkVersion rootProject.ext.ndkVersion 77 | buildToolsVersion rootProject.ext.buildToolsVersion 78 | compileSdk rootProject.ext.compileSdkVersion 79 | 80 | namespace "com.nitroexample" 81 | defaultConfig { 82 | applicationId "com.nitroexample" 83 | minSdkVersion rootProject.ext.minSdkVersion 84 | targetSdkVersion rootProject.ext.targetSdkVersion 85 | versionCode 1 86 | versionName "1.0" 87 | } 88 | signingConfigs { 89 | debug { 90 | storeFile file('debug.keystore') 91 | storePassword 'android' 92 | keyAlias 'androiddebugkey' 93 | keyPassword 'android' 94 | } 95 | } 96 | buildTypes { 97 | debug { 98 | signingConfig signingConfigs.debug 99 | } 100 | release { 101 | // Caution! In production, you need to generate your own keystore file. 102 | // see https://reactnative.dev/docs/signed-apk-android. 103 | signingConfig signingConfigs.debug 104 | minifyEnabled enableProguardInReleaseBuilds 105 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 106 | } 107 | } 108 | 109 | compileOptions { 110 | sourceCompatibility JavaVersion.VERSION_17 111 | targetCompatibility JavaVersion.VERSION_17 112 | } 113 | 114 | kotlinOptions { 115 | jvmTarget = "17" 116 | } 117 | } 118 | 119 | dependencies { 120 | // The version of react-native is set by the React Native Gradle Plugin 121 | implementation("com.facebook.react:react-android") 122 | 123 | if (hermesEnabled.toBoolean()) { 124 | implementation("com.facebook.react:hermes-android") 125 | } else { 126 | implementation jscFlavor 127 | } 128 | 129 | implementation project(":react-native-nitro-palette") 130 | 131 | implementation project(":react-native-nitro-modules") 132 | } 133 | -------------------------------------------------------------------------------- /example/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { 3 | Button, 4 | FlatList, 5 | Image, 6 | SafeAreaView, 7 | StyleSheet, 8 | Text, 9 | View, 10 | useWindowDimensions, 11 | } from "react-native"; 12 | 13 | import RNColorThief from "react-native-color-thief"; 14 | import { getPaletteAsync } from "react-native-nitro-palette"; 15 | import { benchmark } from "./utils/performance-benchmark"; 16 | 17 | const IMAGES = [ 18 | "https://images.unsplash.com/photo-1551410224-699683e15636?q=80&w=2264&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 19 | "https://images.unsplash.com/photo-1721641843496-3c8c60eab024?q=80&w=2274&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 20 | "https://images.unsplash.com/photo-1542051841857-5f90071e7989?q=80&w=2370&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 21 | "https://images.unsplash.com/photo-1731329396266-8250ea4d56c1?q=80&w=2487&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 22 | "https://images.unsplash.com/photo-1500462918059-b1a0cb512f1d?q=80&w=2487&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 23 | "https://images.unsplash.com/photo-1525909002-1b05e0c869d8?q=80&w=2448&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 24 | ]; 25 | 26 | export default function App() { 27 | const [palette, setPalette] = useState(null); 28 | const [index, setIndex] = useState(0); 29 | const { width } = useWindowDimensions(); 30 | const [nitroTime, setNitroTime] = useState(null); 31 | const [thiefTime, setThiefTime] = useState(null); 32 | 33 | const handleGet = async () => { 34 | const result = await benchmark.measure( 35 | "nitro-palette", 36 | async () => { 37 | try { 38 | const colors = await getPaletteAsync(IMAGES[index], 5, 10, true); 39 | setPalette(colors); 40 | } catch (error) { 41 | console.error(error); 42 | } 43 | }, 44 | 10, 45 | ); 46 | console.log("nitro palette"); 47 | console.log(`平均実行時間: ${result.averageTime.toFixed(2)}ms`); 48 | console.log(`最小実行時間: ${result.minTime.toFixed(2)}ms`); 49 | console.log(`最大実行時間: ${result.maxTime.toFixed(2)}ms`); 50 | }; 51 | 52 | const handleThief = async () => { 53 | const result = await benchmark.measure( 54 | "color-thief", 55 | async () => { 56 | try { 57 | const colors = await RNColorThief.getPalette( 58 | IMAGES[index], 59 | 5, 60 | 1, 61 | true, 62 | ); 63 | const rgbColors = colors.map( 64 | (color) => `rgb(${color.r}, ${color.g}, ${color.b})`, 65 | ); 66 | setPalette(rgbColors); 67 | } catch (error) { 68 | console.error(error); 69 | } 70 | }, 71 | 10, 72 | ); 73 | console.log("color thief"); 74 | console.log(`平均実行時間: ${result.averageTime.toFixed(2)}ms`); 75 | console.log(`最小実行時間: ${result.minTime.toFixed(2)}ms`); 76 | console.log(`最大実行時間: ${result.maxTime.toFixed(2)}ms`); 77 | }; 78 | 79 | return ( 80 | 81 | 82 | ( 86 | 87 | 94 | 101 | 102 | 103 | 104 | 105 | )} 106 | keyExtractor={(item) => item} 107 | horizontal 108 | showsHorizontalScrollIndicator={false} 109 | onMomentumScrollEnd={(event) => { 110 | const index = Math.floor( 111 | Math.floor(event.nativeEvent.contentOffset.x) / 112 | Math.floor(event.nativeEvent.layoutMeasurement.width), 113 | ); 114 | setIndex(index); 115 | }} 116 | /> 117 | 118 | 119 | 120 | 121 | Time to get palette:{" "} 122 | {nitroTime ? nitroTime : thiefTime ? thiefTime : ""}{" "} 123 | 124 | 125 | 126 | {palette && ( 127 | 128 | {palette.map((color, index) => ( 129 | 133 | ))} 134 | 135 | )} 136 | 137 |