Skip to content

Commit

Permalink
feat: support load image
Browse files Browse the repository at this point in the history
  • Loading branch information
hans00 committed Dec 30, 2024
1 parent d90f2c3 commit ba0b432
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 1 deletion.
55 changes: 55 additions & 0 deletions android/src/main/java/com/tscprinter/TscCommonModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.tscprinter

import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.bridge.WritableArray

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Base64

import java.net.URL

@ReactModule(name = TscCommonModule.NAME)
class TscCommonModule(reactContext: ReactApplicationContext) :
TscCommonSpec(reactContext) {

override fun getName(): String {
return NAME
}

@ReactMethod
override fun loadImage(uri: String, width: Double, height: Double, promise: Promise) {
try {
val url = URL(uri)
val bitmap = BitmapFactory.decodeStream(url.openStream())
val resizedBitmap = if (width == 0 || height == 0) {
bitmap
} else {
Bitmap.createScaledBitmap(bitmap, width.toInt(), height.toInt(), true)
}
val rawData = IntArray(resizedBitmap.width * resizedBitmap.height)
resizedBitmap.getPixels(rawData, 0, resizedBitmap.width, 0, 0, resizedBitmap.width, resizedBitmap.height)
val data = IntArray(rawData.size)
for (i in rawData.indices) {
val color = rawData[i]
val r = (color shr 16) and 0xFF
val g = (color shr 8) and 0xFF
val b = color and 0xFF
data[i] = (0.299 * r + 0.587 * g + 0.114 * b).toInt()
}
promise.resolve(Arguments.fromArray(data))
} catch (e: Exception) {
promise.reject(e)
}
}

companion object {
const val NAME = "TscCommon"
}
}
7 changes: 7 additions & 0 deletions android/src/newarch/TscCommonSpec.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.tscprinter

import com.facebook.react.bridge.ReactApplicationContext

abstract class TscCommonSpec internal constructor(context: ReactApplicationContext) :
NativeTscCommonSpec(context) {
}
11 changes: 11 additions & 0 deletions android/src/oldarch/TscCommonSpec.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.tscprinter

import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.Promise

abstract class TscCommonSpec internal constructor(context: ReactApplicationContext) :
ReactContextBaseJavaModule(context) {

abstract fun loadImage(uri: String, width: Double, height: Double, promise: Promise)
}
11 changes: 11 additions & 0 deletions ios/TscCommon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifdef RCT_NEW_ARCH_ENABLED
#import "generated/RNTscPrinterSpec/RNTscPrinterSpec.h"

@interface TscCommon : NSObject <NativeTscCommonSpec>
#else
#import <React/RCTBridgeModule.h>

@interface TscCommon : NSObject <RCTBridgeModule>
#endif

@end
88 changes: 88 additions & 0 deletions ios/TscCommon.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#import "TscCommon.h"
#import <UIKit/UIKit.h>

@implementation TscCommon
RCT_EXPORT_MODULE()

RCT_EXPORT_METHOD(loadImage:(NSString *)uri
width:(double)width
height:(double)height
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@try {
NSURL *url = [NSURL URLWithString:uri];
NSData *data;
if ([uri hasPrefix:@"data:"]) {
NSString *base64String = [uri componentsSeparatedByString:@","][1];
data = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
} else {
data = [NSData dataWithContentsOfURL:url];
}

if (!data) {
reject(@"E_LOAD_IMAGE", @"Failed to load image data", nil);
return;
}

UIImage *image = [UIImage imageWithData:data];
if (!image) {
reject(@"E_LOAD_IMAGE", @"Failed to create image from data", nil);
return;
}

// Resize image to target size
UIImage *resizedImage;
if (width == 0 || height == 0) {
resizedImage = image;
} else {
UIGraphicsBeginImageContext(CGSizeMake(width, height));
[image drawInRect:CGRectMake(0, 0, width, height)];
resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}

// Convert to grayscale bitmap
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef context = CGBitmapContextCreate(nil,
resizedImage.size.width,
resizedImage.size.height,
8,
resizedImage.size.width,
colorSpace,
kCGImageAlphaNone);
CGColorSpaceRelease(colorSpace);

CGContextDrawImage(context,
CGRectMake(0, 0, resizedImage.size.width, resizedImage.size.height),
resizedImage.CGImage);

NSData *bitmapData = [NSData dataWithBytes:CGBitmapContextGetData(context)
length:CGBitmapContextGetHeight(context) * CGBitmapContextGetBytesPerRow(context)];
CGContextRelease(context);

resolve(@[
@(resizedImage.size.width),
@(resizedImage.size.height),
bitmapData
]);
} @catch (NSException *exception) {
reject(@"E_LOAD_IMAGE", exception.reason, nil);
}
});
}

#pragma mark - TurboModule

#ifdef RCT_NEW_ARCH_ENABLED

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return std::make_shared<facebook::react::NativeTscBlueSpecJSI>(params);
}

#endif

@end
2 changes: 1 addition & 1 deletion react-native-tsc-printer.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Pod::Spec.new do |s|

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

s.frameworks = "CoreBluetooth", "ExternalAccessory"
s.frameworks = "CoreBluetooth", "ExternalAccessory", "UIKit"

# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
Expand Down
8 changes: 8 additions & 0 deletions src/NativeTscCommon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
loadImage(uri: string, width: number, height: number): Promise<number[]>;
}

export default TurboModuleRegistry.getEnforcing<Spec>('TscCommon');
12 changes: 12 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import net from 'react-native-tcp-socket';
import UsbConnection from './UsbConnection';
import BlueConnection from './BlueConnection';
import Common from './NativeTscCommon';
import { BARCODE_DEFAULT_WIDE, STATUS_MAP } from './constants';
import {
ConnectionType,
Expand Down Expand Up @@ -316,6 +317,17 @@ class Printer {
return this.sendCommand(buildCommand('SET TEAR OFF'));
}

async addImage(
x: number,
y: number,
uri: string,
width: number = 0,
height: number = 0
): Promise<void> {
const data = await Common.loadImage(uri, width, height);
return this.addBitmap(x, y, width, height, new Uint8Array(data));
}

async addBitmap(
x: number,
y: number,
Expand Down

0 comments on commit ba0b432

Please sign in to comment.