Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,68 @@ eas build

> ***Note: This table is only applicable to major versions of react-native-image-marker. Patch versions should be backwards compatible.***

## New Architecture Support

This library fully supports React Native's New Architecture (TurboModules & Fabric) introduced in React Native 0.68+.

### Benefits of the New Architecture

- **Better Performance**: TurboModules provide faster native module initialization and method calls
- **Type Safety**: Enhanced type safety between JavaScript and native code
- **Future Proof**: Aligned with React Native's future direction

### Enabling New Architecture

The library automatically detects and uses the appropriate architecture (old or new) based on your React Native configuration.

#### For React Native 0.70+

To enable the New Architecture in your app:

**iOS:**
```bash
cd ios
RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
```

**Android:**

Add to `android/gradle.properties`:
```properties
newArchEnabled=true
```

#### Compatibility

- ✅ Fully compatible with New Architecture (TurboModules)
- ✅ Backward compatible with the old Bridge architecture
- ✅ Automatic detection - no code changes needed
- ✅ Works with both Hermes and JSC engines

The library will automatically use TurboModules when available, falling back to the traditional bridge architecture when running on older React Native versions or when New Architecture is not enabled.

#### Verifying New Architecture

To verify that the New Architecture is working in your app:

**Check Build Logs:**
- **iOS**: Look for `Building with New Architecture` in Xcode build logs
- **Android**: Check Gradle logs for `IS_NEW_ARCHITECTURE_ENABLED = true`

**Runtime Verification:**
```javascript
// The library automatically uses the best available implementation
// No code changes needed - it just works!
import Marker from 'react-native-image-marker';

// Use the library normally - TurboModules will be used if available
Marker.markText(options).then(result => {
console.log('Image marked:', result);
});
```

The library seamlessly switches between architectures based on your app's configuration, ensuring optimal performance in all scenarios.

## Usage

### Text background fit
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
package com.jimmydaddy.imagemarker

import com.facebook.react.ReactPackage
import com.facebook.react.TurboReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.module.model.ReactModuleInfo
import com.facebook.react.module.model.ReactModuleInfoProvider
import com.facebook.react.uimanager.ViewManager

class ImageMarkerPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
val modules: MutableList<NativeModule> = ArrayList()
modules.add(ImageMarkerManager(reactContext))
return modules
class ImageMarkerPackage : TurboReactPackage() {
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
return if (name == ImageMarkerManager.NAME) {
ImageMarkerManager(reactContext)
} else {
null
}
}

override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
return ReactModuleInfoProvider {
val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
val isTurboModule: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
moduleInfos[ImageMarkerManager.NAME] = ReactModuleInfo(
ImageMarkerManager.NAME,
ImageMarkerManager.NAME,
false, // canOverrideExistingModule
false, // needsEagerInit
true, // hasConstants
false, // isCxxModule
isTurboModule // isTurboModule
)
moduleInfos
}
}
}
1 change: 0 additions & 1 deletion app.plugin.js
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@

module.exports = require('./lib/commonjs/expo-plugin/withImageMarker');
2 changes: 1 addition & 1 deletion example/android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
newArchEnabled=false
newArchEnabled=true

# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
Expand Down
2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"ios": "react-native run-ios",
"start": "react-native start",
"pods": "pod-install",
"m1-pods": "cd ios && arch -x86_64 pod install"
"m1-pods": "cd ios && arch -arm64 pod install"
},
"dependencies": {
"@expo/react-native-action-sheet": "^4.0.1",
Expand Down
2 changes: 1 addition & 1 deletion example/src/bas64bg.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion expo-example/assets/bas64bg.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion expo-example/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = function(api) {
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
Expand Down
5 changes: 5 additions & 0 deletions ios/RCTImageMarker/RCTImageMarkerBridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ @interface RCT_EXTERN_MODULE(ImageMarker, NSObject)
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)

+ (BOOL)requiresMainQueueSetup
{
return NO;
}

@end
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-image-marker",
"version": "1.2.9",
"version": "1.3.0",
"description": "Add text or icon watermark to your images",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down
27 changes: 27 additions & 0 deletions src/NativeImageMarker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

/**
* TurboModule spec for ImageMarker native module.
*
* Note: TurboModule specs use generic types (Object) for codegen compatibility.
* The actual TypeScript interfaces (TextMarkOptions, ImageMarkOptions) are
* maintained in index.ts for type-safe API usage.
*/
export interface Spec extends TurboModule {
/**
* Mark text on background image
* @param opts TextMarkOptions object containing background image and text watermark options
* @returns Promise resolving to image path or base64 string
*/
markWithText(opts: Object): Promise<string>;

/**
* Mark image watermark on background image
* @param opts ImageMarkOptions object containing background and watermark image options
* @returns Promise resolving to image path or base64 string
*/
markWithImage(opts: Object): Promise<string>;
}

export default TurboModuleRegistry.getEnforcing<Spec>('ImageMarker');
28 changes: 17 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { NativeModules, Platform, Image } from 'react-native';
import {
NativeModules,
Platform,
Image,
TurboModuleRegistry,
} from 'react-native';

const { resolveAssetSource } = Image;
const LINKING_ERROR =
Expand Down Expand Up @@ -825,16 +830,17 @@ export interface ImageMarkOptions {
watermarkImages: Array<WatermarkImageOptions>;
}

const ImageMarker = NativeModules.ImageMarker
? NativeModules.ImageMarker
: new Proxy(
{},
{
get() {
throw new Error(LINKING_ERROR);
},
}
);
const ImageMarker =
TurboModuleRegistry.get('ImageMarker') ??
NativeModules.ImageMarker ??
new Proxy(
{},
{
get() {
throw new Error(LINKING_ERROR);
},
}
);

class Marker {
/** @ignore ignore constructors for typedoc only */
Expand Down