Skip to content
Merged
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
18 changes: 13 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,19 @@ example/android/
example/dist/
example/build/
example/.bundle/
example/.watchmanconfig
example/Gemfile
example/jest.config.js
example/metro.config.js
example/react-native.config.js

example/.yarn/*
!example/.yarn/patches
!example/.yarn/plugins
!example/.yarn/releases
!example/.yarn/sdks
!example/.yarn/versions

example/.yarn/cache
example/.yarn/unplugged
example/.yarn/build-state.yml
example/.yarn/install-state.gz
example/.pnp.*

# Expo build artifacts
example/.expo/
Expand Down
2 changes: 2 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ turbo.json
# Build and development
example/
modules/
scripts/
test-install/
android/build/
ios/build/
.turbo/
Expand Down
62 changes: 14 additions & 48 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,62 +5,28 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.0] - 2025-08-28
## [1.1.0] - 2025-09-05

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Breaking change requires a major version bump (SemVer).

You’re changing the return type of a public API; that’s an incompatible change. Bump to 2.0.0 (or make the change backward‑compatible and keep 1.1.0).

Apply:

-## [1.1.0] - 2025-09-05
+## [2.0.0] - 2025-09-05
@@
-- **Breaking Change**: `ImageCodeScanner.scan()` now returns `ScanResult[]` instead of `string[]`
+- **Breaking Change**: `ImageCodeScanner.scan()` now returns `ScanResult[]` instead of `string[]`

And update the release link below accordingly:

-[1.1.0]: https://github.com/nguyenthanhan/react-native-image-code-scanner/releases/tag/v1.1.0
+[2.0.0]: https://github.com/nguyenthanhan/react-native-image-code-scanner/releases/tag/v2.0.0

Also applies to: 20-20

🤖 Prompt for AI Agents
In CHANGELOG.md around line 8, the release entry incorrectly uses 1.1.0 despite
a breaking public API change; update the version to 2.0.0 and adjust any release
links referenced below to point to the 2.0.0 tag/compare URL (and mirror the
same change wherever else this changelog entry is duplicated, per "Also applies
to: 20-20"). Ensure the header reads "## [2.0.0] - 2025-09-05" and update the
release link section at the bottom to reference 2.0.0.


### Added

- Initial release of React Native Image Code Scanner
- Native implementation for iOS using Vision Framework
- Native implementation for Android using ML Kit
- Support for 13 barcode formats (QR Code, Code 128, Code 39, etc.)
- **Automatic image preprocessing** for optimal recognition:
- Contrast enhancement
- Grayscale conversion
- Multiple rotation attempts (0°, 90°, 180°, 270°)
- **Ultra-simple API** - just pass image path and formats, preprocessing is automatic by default
- Full support for React Native's New Architecture (Turbo Modules)
- TypeScript support with complete type definitions
- Comprehensive documentation and examples
- **Expo compatibility** with prebuild support
- **Expo example app** with modern UI and full feature demonstration
- Cross-platform example app (iOS, Android, Web)
- **Enhanced scan results** - Now returns both content and format information
- New `ScanResult` interface with `content` and `format` properties
- Format detection for all supported barcode types (QR_CODE, CODE_128, EAN_13, etc.)
- Updated example app to display both content and barcode format
- TypeScript support for the new result format

### Changed

- **Major Version Release**: Stable 1.0.0 release with production-ready features
- Enhanced CI pipeline and build reliability
- Improved cross-platform compatibility
- **Breaking Change**: `ImageCodeScanner.scan()` now returns `ScanResult[]` instead of `string[]`
- Updated API to provide more detailed scan results
- Enhanced example app UI to show barcode format alongside content
- Improved result display with format badges

### Fixed

- Resolved CI and Android build issues with Yarn lockfile and JVM compatibility
- Improved build pipeline stability
- Enhanced cross-platform build reliability
- CI pipeline improvements and stability enhancements
- Android build compatibility improvements
- Yarn lockfile consistency fixes
- Better type safety with comprehensive result interface
- Enhanced debugging capabilities with format information

### Features
[1.1.0]: https://github.com/nguyenthanhan/react-native-image-code-scanner/releases/tag/v1.1.0

- Lightweight and performant native implementation
- **Automatic preprocessing** enabled by default for best results
- Smart retry logic with multiple image enhancement techniques
- No additional setup required for Android
- Minimal iOS setup with just pod install
- **Expo integration** with proper prebuild workflow
- **Modern example app** using Expo Image Picker and StatusBar
- **Simplified API** - just pass image path and formats
- **Performance metrics** and timing measurements

### Example App Features

- Modern Expo-based example application
- Barcode format selection UI with real-time toggles
- Automatic preprocessing info with optional disable switch
- Improved error handling and user feedback
- Comprehensive setup documentation
- Support for both Expo Go (UI testing) and prebuild (full functionality)
- Cross-platform compatibility (iOS, Android, Web)
- Performance timing and metrics display

[1.0.0]: https://github.com/nguyenthanhan/react-native-image-code-scanner/releases/tag/v1.0.0
_This changelog will be updated with each new release to document all changes, improvements, and new features._
Comment on lines +30 to +32

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify release link/tag exists before merging.

If you adopt 2.0.0, update the link; otherwise keep 1.1.0 and drop “Breaking.” Quick check:


🏁 Script executed:

#!/bin/bash
# Verify GitHub release tag and npm version alignment
gh release view v2.0.0 || gh release view v1.1.0
npm view react-native-image-code-scanner version

Length of output: 284


🏁 Script executed:

#!/bin/bash
# Check for GitHub release tags via GitHub API
for tag in v1.1.0 v2.0.0; do
  status=$(curl -s -o /dev/null -w "%{http_code}" https://api.github.com/repos/nguyenthanhan/react-native-image-code-scanner/releases/tags/$tag)
  echo "$tag: HTTP $status"
done

# Confirm published npm version
npm view react-native-image-code-scanner version

Length of output: 498


Ensure GitHub release and npm package for v1.1.0 exist before merging.

Changelog link [1.1.0] points to a non-existent GitHub tag (HTTP 404) and npm shows latest version 1.0.0. Publish the v1.1.0 release (and bump npm) or adjust the changelog to reference an existing version.

🤖 Prompt for AI Agents
CHANGELOG.md around lines 30-32: the [1.1.0] release link points to a missing
GitHub tag and npm still shows 1.0.0; either create and push the v1.1.0 GitHub
release/tag and publish the v1.1.0 package to npm so the link and version are
valid, or update the changelog to reference an existing published version (e.g.,
change link and label to v1.0.0 or remove the unreleased entry) and keep
changelog and package version consistent before merging.

74 changes: 46 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ A lightweight, high-performance React Native library for scanning QR codes and b
| **0.79.x** | ✅ **1.0.x** | **New Architecture (default)** | **Latest - Full Support** |
| 0.80.x+ | 🔜 1.0.x | New Architecture | Ready when released |

**Latest Version**: v1.0.0 - Major stable release with enhanced CI pipeline and build reliability improvements

### Requirements

- **React Native**: >=0.70.0
Expand Down Expand Up @@ -129,15 +127,19 @@ npx expo run:android
### Basic Usage

```typescript
import ImageCodeScanner from 'react-native-image-code-scanner';
import ImageCodeScanner, { ScanResult } from 'react-native-image-code-scanner';

// Scan QR code from image
const scanQRCode = async (imagePath: string) => {
try {
const results = await ImageCodeScanner.scan({ path: imagePath });
const results: ScanResult[] = await ImageCodeScanner.scan({
path: imagePath,
});

if (results.length > 0) {
console.log('QR Code found:', results[0]);
const firstResult = results[0];
console.log('QR Code found:', firstResult.content);
console.log('Format:', firstResult.format); // "QR_CODE"
} else {
console.log('No QR code found in image');
}
Expand All @@ -152,11 +154,12 @@ const scanQRCode = async (imagePath: string) => {
```typescript
import ImageCodeScanner, {
BarcodeFormat,
ScanResult,
} from 'react-native-image-code-scanner';

const scanMultipleFormats = async (imagePath: string) => {
try {
const results = await ImageCodeScanner.scan({
const results: ScanResult[] = await ImageCodeScanner.scan({
path: imagePath,
formats: [
BarcodeFormat.QR_CODE,
Expand All @@ -166,7 +169,10 @@ const scanMultipleFormats = async (imagePath: string) => {
// Automatic preprocessing is enabled by default for optimal recognition
});

console.log('Found barcodes:', results);
results.forEach((result, index) => {
console.log(`Barcode ${index + 1}:`, result.content);
console.log(`Format:`, result.format);
});
} catch (error) {
console.error('Scan error:', error);
}
Expand All @@ -187,7 +193,7 @@ As soon as a barcode is detected with any technique, the result is returned imme
### With Image Picker

```typescript
import ImageCodeScanner from 'react-native-image-code-scanner';
import ImageCodeScanner, { ScanResult } from 'react-native-image-code-scanner';
import { launchImageLibrary } from 'react-native-image-picker';
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const scanFromGallery = async () => {
Expand All @@ -199,14 +205,17 @@ const scanFromGallery = async () => {
if (result.assets && result.assets[0]) {
const imagePath = result.assets[0].uri;

const scanResults = await ImageCodeScanner.scan({
const scanResults: ScanResult[] = await ImageCodeScanner.scan({
path: imagePath,
formats: [ImageCodeScanner.BarcodeFormat.QR_CODE],
// Automatic preprocessing is enabled by default
});

if (scanResults.length > 0) {
console.log('Barcode data:', scanResults);
scanResults.forEach((result) => {
console.log('Content:', result.content);
console.log('Format:', result.format);
});
}
}
};
Expand All @@ -215,7 +224,7 @@ const scanFromGallery = async () => {
### With Expo Image Picker

```typescript
import ImageCodeScanner from 'react-native-image-code-scanner';
import ImageCodeScanner, { ScanResult } from 'react-native-image-code-scanner';
import * as ImagePicker from 'expo-image-picker';
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const scanFromGallery = async () => {
Expand All @@ -228,14 +237,17 @@ const scanFromGallery = async () => {
if (!result.canceled && result.assets && result.assets[0]) {
const imagePath = result.assets[0].uri;

const scanResults = await ImageCodeScanner.scan({
const scanResults: ScanResult[] = await ImageCodeScanner.scan({
path: imagePath,
formats: [ImageCodeScanner.BarcodeFormat.QR_CODE],
// Automatic preprocessing is enabled by default
});

if (scanResults.length > 0) {
console.log('Barcode data:', scanResults);
scanResults.forEach((result) => {
console.log('Content:', result.content);
console.log('Format:', result.format);
});
}
}
};
Expand All @@ -246,18 +258,23 @@ const scanFromGallery = async () => {
```typescript
import ImageCodeScanner, {
BarcodeFormat,
ScanResult,
} from 'react-native-image-code-scanner';

// Scan with automatic preprocessing and multiple formats
const scanEverything = async (imagePath: string) => {
const scanEverything = async (imagePath: string): Promise<ScanResult[]> => {
try {
const results = await ImageCodeScanner.scan({
const results: ScanResult[] = await ImageCodeScanner.scan({
path: imagePath,
formats: Object.values(BarcodeFormat), // All supported formats
// Automatic preprocessing is enabled by default
});

console.log(`Found ${results.length} barcodes:`, results);
console.log(`Found ${results.length} barcodes:`);
results.forEach((result, index) => {
console.log(`${index + 1}. ${result.format}: ${result.content}`);
});

Comment thread
coderabbitai[bot] marked this conversation as resolved.
return results;
} catch (error) {
console.error('Scan failed:', error);
Expand Down Expand Up @@ -289,7 +306,16 @@ interface ScanOptions {

#### Returns

`Promise<string[]>` - Array of decoded barcode values
`Promise<ScanResult[]>` - Array of scan results with content and format information

#### ScanResult

```typescript
interface ScanResult {
content: string; // The decoded barcode content
format: string; // The detected barcode format (e.g., "QR_CODE", "EAN_13")
}
```

### `ImageCodeScanner.BarcodeFormat`

Expand Down Expand Up @@ -396,8 +422,8 @@ The example app demonstrates:

**Platform Support:**

- 📱 **iOS**: Full camera and gallery access
- 🤖 **Android**: Full camera and gallery access
- 📱 **iOS**: Gallery access
- 🤖 **Android**: Gallery access

## 🤝 Contributing

Expand All @@ -413,18 +439,10 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f

## 📄 License

MIT © [Heimer Nguyen](https://github.com/nguyenthanhan)
MIT

## 🆘 Support

- 🐛 [Report Issues](https://github.com/nguyenthanhan/react-native-image-code-scanner/issues)
- 💬 [Discussions](https://github.com/nguyenthanhan/react-native-image-code-scanner/discussions)
- ⭐ Star us on [GitHub](https://github.com/nguyenthanhan/react-native-image-code-scanner)

## 📝 Changelog

See [CHANGELOG.md](CHANGELOG.md) for version history.

---

Made with ❤️ by [Heimer Nguyen](https://github.com/nguyenthanhan)
2 changes: 1 addition & 1 deletion RNImageCodeScanner.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Pod::Spec.new do |s|
s.platforms = { :ios => "13.4" }
s.source = { :git => "https://github.com/nguyenthanhan/react-native-image-code-scanner.git", :tag => "#{s.version}" }

s.source_files = "ios/**/*.{h,m,mm,swift}"
s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
s.swift_version = "5.0"

# Required frameworks for Vision and image processing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,30 @@ class ImageCodeScannerModule(reactContext: ReactApplicationContext) :
val codes = barcodes
.mapNotNull { barcode ->
val value = barcode.displayValue ?: barcode.rawValue
value
if (value != null && value.isNotEmpty()) {
val format = when (barcode.format) {
Barcode.FORMAT_QR_CODE -> "QR_CODE"
Barcode.FORMAT_CODE_128 -> "CODE_128"
Barcode.FORMAT_CODE_39 -> "CODE_39"
Barcode.FORMAT_CODE_93 -> "CODE_93"
Barcode.FORMAT_EAN_13 -> "EAN_13"
Barcode.FORMAT_EAN_8 -> "EAN_8"
Barcode.FORMAT_UPC_A -> "UPC_A"
Barcode.FORMAT_UPC_E -> "UPC_E"
Barcode.FORMAT_PDF417 -> "PDF_417"
Barcode.FORMAT_DATA_MATRIX -> "DATA_MATRIX"
Barcode.FORMAT_AZTEC -> "AZTEC"
Barcode.FORMAT_ITF -> "ITF"
Barcode.FORMAT_CODABAR -> "CODABAR"
else -> "UNKNOWN"
}
val resultMap = Arguments.createMap()
resultMap.putString("content", value)
resultMap.putString("format", format)
resultMap
} else null
}
.filter { it.isNotEmpty() }
.filter { it != null }

val arr = Arguments.fromList(codes)
promise.resolve(arr)
Expand Down
Loading