
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
sunmi-external-printer
Advanced tools
❗❗❗❗Warning This Package only works for Android ❗❗❗❗
A react native library for sunmi external printer. Only tested on Sunmi Cloud Printer NT311.
npm install sunmi-external-printer
import { base64Image } from '../base64image';
import * as React from 'react';
import {
StyleSheet,
View,
Text,
Button,
SafeAreaView,
ScrollView,
StatusBar,
useColorScheme,
TouchableOpacity,
FlatList,
PermissionsAndroid,
} from 'react-native';
import { Colors, Header } from 'react-native/Libraries/NewAppScreen';
import {
EscPosImageWithTCPConnectionBitImageWrapper,
EscPosImageWithTCPConnectionGraphicsImageWrapper,
EscPosImageWithTCPConnectionRasterBitImageWrapper,
openDrawer,
printImageByBluetooth,
scanBLDevice,
startNetworkDiscovery,
stopNetworkDiscovery,
} from 'sunmi-external-printer';
import { DeviceEventEmitter } from 'react-native';
import { useState } from 'react';
import { convertHTMLtoBase64 } from '../../src';
import type { printerDevice } from 'src/printerDevice';
function App(): JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
const [ipAddress, setIpAddress] = useState<string>('');
const [port, setPort] = useState<string>('');
const [printerName, setPrinterName] = useState<string>('');
const [devices, setListofDevices] = useState<ItemData[]>([]);
const [currPrinter, setCurrPrinter] = useState<printerDevice | null>(null);
const [blDevices, setListofBlDevices] = useState<printerDevice[]>([]);
const [showFlatListNetwork, setShowFlatListNetwork] = useState<boolean>(true);
const [showFlatListBT, setShowFlatListBT] = useState<boolean>(false);
const Item2 = ({ item, onPress, backgroundColor, textColor }: any) => (
<TouchableOpacity
onPress={onPress}
style={[styles.item, { backgroundColor }]}
>
<Text style={[styles.title, { color: textColor }]}>{item.name}</Text>
<Text style={[styles.title, { color: textColor }]}>{item.address}</Text>
</TouchableOpacity>
);
const renderItem2 = ({ item }: { item: printerDevice }) => {
const backgroundColor =
item.name ===
(currPrinter === null ? ' ' : (currPrinter!!.name as string))
? '#00008B'
: 'blue';
return (
<Item2
item={item}
onPress={async () => {
setCurrPrinter(item);
}}
backgroundColor={backgroundColor}
textColor={'white'}
/>
);
};
const renderItem = ({ item }: { item: ItemData }) => {
const backgroundColor =
item.printerIPAddress === ipAddress ? '#00008B' : 'blue';
return (
<Item
item={item}
onPress={async () => {
setIpAddress(item.printerIPAddress);
setPort(item.printerPort);
setPrinterName(item.printerName);
const Print = await stopNetworkDiscovery();
DeviceEventEmitter.removeAllListeners();
setListofDevices([]);
console.log(Print);
}}
backgroundColor={backgroundColor}
textColor={'white'}
/>
);
};
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};
return (
<SafeAreaView style={backgroundStyle}>
<StatusBar
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
backgroundColor={backgroundStyle.backgroundColor}
/>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={backgroundStyle}
>
<Header />
<View
style={{
backgroundColor: isDarkMode ? Colors.black : Colors.white,
}}
>
<Button
title="Print with Graphic Image Wrapper"
onPress={async () => {
const Print =
await EscPosImageWithTCPConnectionGraphicsImageWrapper(
base64Image,
ipAddress,
port
);
console.log(Print);
}}
/>
<Button
title="Print with Bit Wrapper"
onPress={async () => {
const Print = await EscPosImageWithTCPConnectionBitImageWrapper(
base64Image,
ipAddress,
port
);
console.log(Print);
}}
/>
<Button
title="Print with Raster Bit Wrapper "
onPress={async () => {
const Print =
await EscPosImageWithTCPConnectionRasterBitImageWrapper(
base64Image,
ipAddress,
port
);
console.log(Print);
}}
/>
<Button
title="Start Network Discovery"
onPress={async () => {
const networkDiscovery = await startNetworkDiscovery();
DeviceEventEmitter.addListener('OnPrinterFound', (event) => {
const device: ItemData = {
printerName: event.printername,
printerIPAddress: event.ip,
printerPort: event.port,
};
setListofDevices([...devices, device]);
});
setListofBlDevices([]);
setShowFlatListBT(false);
setShowFlatListNetwork(true);
console.log(networkDiscovery);
}}
/>
<Button
title="Stop Discovery"
onPress={async () => {
const Print = await stopNetworkDiscovery();
DeviceEventEmitter.removeAllListeners();
setListofDevices([]);
setShowFlatListNetwork(false);
setShowFlatListBT(true);
console.log(Print);
}}
/>
<Button
title="Convert HTMl to Image"
onPress={async () => {
const Print = await convertHTMLtoBase64(
'' +
'<html>\n' +
'<head>\n' +
'<style>\n' +
'body {\n' +
' background-color: lightblue;\n' +
'}\n' +
'\n' +
'h1 {\n' +
' text-align: center;\n' +
'}\n' +
'\n' +
'p {\n' +
' font-family: verdana;\n' +
' font-size: 20px;\n' +
'}\n' +
'p.korean {\n' +
' font-family: Single Day;\n' +
' font-size: 20px;\n' +
'}\n' +
'</style>\n' +
'</head>' +
'<body>' +
'<h1>Hello, world.</h1>' +
'<p>الصفحة الرئيسية \n' + // Arabiac
'<br>你好,世界 \n' + // Chinese
'<br>こんにちは世界 \n' + // Japanese
'<br>Привет мир \n' + // Russian
'<br>नमस्ते दुनिया \n' + // Hindi
'<p class="korean"><br>안녕하세요 세계</p>' + // if necessary, you can download and install on your environment the Single Day from fonts.google...
'</body>',
400
);
console.log(Print);
}}
/>
<Button
title="Open Drawer"
onPress={async () => {
const drawer = await openDrawer(ipAddress, port);
console.log(drawer);
}}
/>
<Button
title="startBTDisovery"
onPress={async () => {
const requestBLPermissions = async () => {
const res = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION!!
);
await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN!!,
PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT!!,
]);
console.log(res);
};
await requestBLPermissions();
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN!!,
{
title: 'Android Scan Permission',
message: 'Scan Bluetooth Permission',
buttonNeutral: 'A ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
}
);
if (granted) {
const results = await scanBLDevice();
console.log(results);
setListofBlDevices(results);
setShowFlatListBT(true);
setShowFlatListNetwork(false);
setListofDevices([]);
}
}}
/>
<Button
title="printImageByBluetooth"
onPress={async () => {
const result = await printImageByBluetooth(
currPrinter!!,
base64Image
);
console.log(result);
}}
/>
<Text style={{ alignSelf: 'center', fontSize: 20, marginTop: 10 }}>
Current IP Printer Device:{printerName}
</Text>
<Text style={{ alignSelf: 'center', fontSize: 20, marginTop: 10 }}>
IPAddress:{ipAddress}
</Text>
<Text style={{ alignSelf: 'center', fontSize: 20, marginTop: 10 }}>
Port:{port}
</Text>
<Text style={{ alignSelf: 'center', fontSize: 20, marginTop: 10 }}>
Current BTPrinter:{currPrinter == null ? ' ' : currPrinter.name}{' '}
{currPrinter == null ? ' ' : currPrinter.address}
</Text>
</View>
</ScrollView>
<View style={{ borderWidth: 5, height: 300 }}>
{showFlatListBT && (
<FlatList
data={blDevices}
renderItem={renderItem2}
keyExtractor={(item) => item.address}
extraData={currPrinter}
/>
)}
{showFlatListNetwork && (
<FlatList
data={devices}
renderItem={renderItem}
keyExtractor={(item) => item.printerIPAddress}
extraData={ipAddress}
/>
)}
</View>
</SafeAreaView>
);
}
type ItemData = {
printerName: string;
printerIPAddress: string;
printerPort: string;
};
type ItemProps = {
item: ItemData;
onPress: () => void;
backgroundColor: string;
textColor: string;
};
const Item = ({ item, onPress, backgroundColor, textColor }: ItemProps) => (
<TouchableOpacity
onPress={onPress}
style={[styles.item, { backgroundColor }]}
>
<Text style={[styles.title, { color: textColor }]}>
{item.printerIPAddress}
</Text>
<Text style={[styles.title, { color: textColor }]}>{item.printerName}</Text>
<Text style={[styles.title, { color: textColor }]}>{item.printerPort}</Text>
</TouchableOpacity>
);
const styles = StyleSheet.create({
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
},
highlight: {
fontWeight: '700',
},
item: {
flex: 1,
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 10,
},
devicesContainer: {
height: '300',
},
});
export default App;
For futher details please see the example folder
startNetworkDiscovery()
| Parameters | Required | Type | Description |
|---|---|---|---|
| (void) | - | - | starts a device event emitter listener. To listen to the event add a listener that listens to ‘On Printer Found’ |
stopNetworkDiscovery()
| Parameters | Required | Type | Description |
|---|---|---|---|
| (void) | - | - | Stops Network Discovery, make sure to also close your device event emitter |
EscPosImageWithTCPConnectionBitImageWrapper
| Parameters | Required | Type | Description |
|---|---|---|---|
| base64Image | true | String | Print base64 image, remove the data:image; prefix if it has it. |
| ipAddress | true | String | ipAddress of the printer |
| port | true | String | port of the printer (is usally 9100) |
EscPosImageWithTCPConnectionGraphicsImageWrapper
| Parameters | Required | Type | Description |
|---|---|---|---|
| base64Image | true | String | Print base64 image, remove the data:image; prefix if it has it. |
| ipAddress | true | String | ipAddress of the printer |
| port | true | String | port of the printer (is usally 9100) |
EscPosImageWithTCPConnectionRasterBitImageWrapper
| Parameters | Required | Type | Description |
|---|---|---|---|
| base64Image | true | String | Print base64 image, remove the data:image; prefix if it has it. |
| ipAddress | true | String | ipAddress of the printer |
| port | true | String | port of the printer (is usally 9100) |
Only tested on Sunmi Cloud Printer NT311, The Printed Images are also only tested on width of 80mm.
Note: If an image size is larger or or smaller than 80mm, scale it down to the printer width first.
scanBLDevice
Returns a list of filtered (just printers) and non-filtered bluetooth devices (not just printers) after roughly 12 seconds of scanning period with the name and MAC address.
printImageByBluetooth
printing an Image by Bluetooth and initiates a full cut at the end , uses the BitonalOrderDither algorithm
| Parameters | Required | Type | Description |
|---|---|---|---|
| device | true | String | pass the device |
| base64Image | true | String | base64 image, remove the data:image; prefix if it has it. |
See the contributing guide to learn how to contribute to the repository and the development workflow.
MIT
Made with create-react-native-library
FAQs
Printing Module for Printing Images with Sunmi in React Native
The npm package sunmi-external-printer receives a total of 9 weekly downloads. As such, sunmi-external-printer popularity was classified as not popular.
We found that sunmi-external-printer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.