react-native-star-io10 icon indicating copy to clipboard operation
react-native-star-io10 copied to clipboard

Generate and print image in react-native

Open dkchiem opened this issue 3 years ago • 17 comments

I'm using this library in a react-native app to print text with my thermal printer (bluetooth). However, when I print, it always prints a short black paper and cuts. I know the problem is not with the printer, because I printed a self test (holding power + feed button) and it worked. There's also no error in the console when printing.

Here are my printer details: Model: TSP100IIIBI Firmware: 2.0 Version of react-native-star-io10: 1.0.0

Here is the part of my code that prints:

function print() {
        const printerSettings = new StarConnectionSettings();
        printerSettings.interfaceType = this.state.settings.interfaceType;
        printerSettings.identifier = this.state.settings.identifier;
        const printer = new StarPrinter(printerSettings);

        try {
            await printer.open();
            const builder = new StarXpandCommand.StarXpandCommandBuilder();
            builder.addDocument(
                new StarXpandCommand.DocumentBuilder().addPrinter(
                    new StarXpandCommand.PrinterBuilder()
                        .styleInternationalCharacter(
                            StarXpandCommand.Printer.InternationalCharacterType.Usa,
                        )
                        .styleCharacterSpace(0)
                        .styleAlignment(StarXpandCommand.Printer.Alignment.Center)
                        .styleBold(true)
                        .actionPrintText('Test\n')
                        .actionCut(StarXpandCommand.Printer.CutType.Partial),
                ),
            );
            const commands = await builder.getCommands();

            await printer.print(commands);
        } catch (error) {
            if (error instanceof StarIO10Error) {
                Alert.alert('Could not print', error.message);
            }
        } finally {
            await printer.close();
            await printer.dispose();
        }
    }

dkchiem avatar May 06 '21 04:05 dkchiem

@Doudou8 Since TSP100 is a Raster-only printer, it does not support the actionPrintText and cannot print text-based data.

Instead, it will be needed to build up your document as image data and add them to the print job with the actionPrintImage method.

Due to differences in device capabilities, not all PrinterBuilder methods are available on every device. The supported/unsupported methods for each device are listed in the "Supported Model" column above each method.

bandit-ibayashi avatar May 06 '21 08:05 bandit-ibayashi

@bandit-ibayashi Is there any example in the documentation?

Samuel-Martineau avatar May 06 '21 13:05 Samuel-Martineau

@Samuel-Martineau If you mean sample to create a receipt image data, unfortunately there are no samples to provide. If you are looking for a sample code to print an image, you may find line 43 of the following file helpful: Replace logo_01.png with the receipt data and delete lines 44 to 99 to try printing. https://github.com/star-micronics/react-native-star-io10/blob/master/example/samples/printing/App.tsx

bandit-ibayashi avatar May 12 '21 02:05 bandit-ibayashi

@bandit-ibayashi I got StarIO10ArgumentError when replace logo_01.png with my receipt data. Could you describe the step more specifically. The error says Invalid source. .actionPrintImage( new StarXpandCommand.Printer.ImageParameter( "SKIPLI\n---- Test Order ----\nEmily Miller\n4 items\nDelivery\nCourier: Postmates\n\n Order# : 44BuAE\nJan-12-2020 10:47 AM\n\n", 406, ), )

nguyen-vo avatar Jun 04 '21 18:06 nguyen-vo

Hi @nguyen-vo I'm sorry no one responded to you sooner but the ImageParameter method does not convert text to an image, so this result is expected. You need to provide an image file as a parameter.

Hope this helps!

gare-bear avatar Jun 21 '21 17:06 gare-bear

@gare-bear thank for your response, so is there a way we can generate an image file inside drawable folder on the fly? Do you have any recommendation?

nguyen-vo avatar Jun 21 '21 17:06 nguyen-vo

@nguyen-vo react-native-canvas seems like it could be a good choice. disclaimer: I haven't used it myself.

When researching I didn't find a lot of options. Most options I found were for simpler tasks, like cropping, filters, re-sizing, etc.

Let me know if you find any other good options!

gare-bear avatar Jun 22 '21 17:06 gare-bear

Thank you. I will let you know if this work

nguyen-vo avatar Jun 22 '21 17:06 nguyen-vo

@gare-bear I would vote for raster receipt printing support as well. It'd be great if we can do something similar to this https://github.com/auctifera-josed/starprnt/blob/master/README.md#print-raster-receipt

TSP143III is commonly-used printers among my clients and I'd rather support them than asking them to buy new printers. Although I can generate a receipt image from the server and send back to the app as a workaround, I'd prefer function like above example that can do raster receipt from within the app.

piyasil avatar Sep 16 '21 16:09 piyasil

With the help of component capture, it's very convenient to make custom templates and generate images for printing. Check out this lib https://github.com/gre/react-native-view-shot

piyasil avatar Sep 30 '21 07:09 piyasil

Hi Trying to make this work with react-native-view-shot and it works fine on android, but not on iOS, throws an Invalid source error:

15:21:46.888 instrument.js:111 StarIO10ArgumentError: Invalid source.
    at _buildObject$ (StarIO10ErrorFactory.ts:40)
    at tryCatch (runtime.js:63)
    at Generator.invoke [as _invoke] (runtime.js:294)
    at Generator.next (runtime.js:119)
    at tryCatch (runtime.js:63)
    at invoke (runtime.js:155)
    at runtime.js:190
    at tryCallTwo (core.js:45)
    at doResolve (core.js:200)
    at new Promise (core.js:66)

If I generate the image as base64 image and feed it to an <Image... component, it shows the captured image, so the file is there for sure and accessible.

Anyone had any luck on iOS printing the image that has been created with https://github.com/gre/react-native-view-shot?

ksgy avatar Nov 02 '21 15:11 ksgy

@bandit-ibayashi what image sources do we support with the Xpand SDK? The two I know of are:

  1. local asset from a file
  2. image from a secure url

what about generating/printing images on the fly, how can we print those?

gare-bear avatar Nov 23 '21 01:11 gare-bear

@piyasil Thanks for your direction! It works!

@ksgy iOS iPad dev here, I managed to get react-native-view-shot working with react-native-svg. Sample code as below:

import Svg, { Line, SvgProps, Text as SvgText, TSpan } from 'react-native-svg';
import ViewShot, { captureRef } from "react-native-view-shot";

const pixelWidth = 576;
const App =() => {
  // you can change printerId by inserting a text field
  const [printerId, setPrinterId] = useState<string>('YOUR_PRINTER_IP_OR_MAC');
  const foo = useRef<Component<SvgProps, any, any> | null>();
  
  const trialSvg = () => {
    return (
      <Svg height="500" width={pixelWidth} fill='black'>
        <SvgText y="20" dx="5 5">
          <TSpan x="10">tspan line 1</TSpan>
          <TSpan fontSize="12" >font size 12</TSpan>
          <TSpan fontSize="14" >font size 14</TSpan>
          <TSpan fontSize="16" >font size 16</TSpan>
        </SvgText>
      </Svg>
    )
  }
  
  // official example code
  async function print(address: string): Promise<void> {
    // Specify your printer connection settings.
    var settings = new StarConnectionSettings();
    settings.interfaceType = InterfaceType.Lan;
    settings.identifier = address;
    var printer = new StarPrinter(settings);

    try {
      // Connect to the printer.
      await printer.open();

      // capture svg under the reference view
      const bar = await captureRef((foo.current as any), {
        format: "jpg",
        quality: 0.8,
        result: 'base64',
        width: pixelWidth,
      })
      .then(
        base64 => {
          console.log("Image captured and saved as base64:", base64);
          return base64
        }
      )
      .catch(error => console.log(error));

      // create printing data. (Please refer to 'Create Printing data')
      var builder = new StarXpandCommand.StarXpandCommandBuilder();

      builder.addDocument(new StarXpandCommand.DocumentBuilder()
        .addPrinter(new StarXpandCommand.PrinterBuilder()
          .actionPrintImage(new StarXpandCommand.Printer.ImageParameter(bar as string, pixelWidth))
          .actionCut(StarXpandCommand.Printer.CutType.Partial)
        )
      )

      // ...
      var commands = await builder.getCommands();

      // Print.
      await printer.print(commands);

      console.log(`Success`);
    }
    catch(error) {
      // Error.
      console.log('error')
      console.log(error);
    }
    finally {
      // Disconnect from the printer and dispose object.
      await printer.close();
      await printer.dispose();
    }
  }

  return (
    <ScrollView
      contentInsetAdjustmentBehavior="automatic"
      contentContainerStyle={{
        alignItems: 'center',
      }}>
      <View>
        <Button mode='contained' onPress={async () =>  { await print(printerId) }}>
          {t('printBtn')}
        </Button>
      </View>
      <ViewShot>
        <View ref={ref => foo.current = ref}>
          {trialSvg()}
        </View>
      </ViewShot>
    </ScrollView>
  )
}

Notes:

  1. pay special notices to React's ref foo = useRef<...>() & its capturing method bar = await captureRef(...)
  2. const pixelWidth = 576; as 'TSP100III has a pixel width of 576 dots' (credit to: @gare-bear; source: https://github.com/star-micronics/react-native-star-io10/issues/33)
  3. I suspect feeding to an <Image... component may the error cause, <ViewShot> <View> ... </ViewShot> </View> could be safer?

@gare-bear and there is 3rd supporting format: Base64 encoded contents I generate the base64 on the fly - you can check out above sample code bar

  1. const bar = await captureRef(...) - you can uncomment console.log to see the result non-uri base64 string
  2. new StarXpandCommand.Printer.ImageParameter(bar as string, pixelWidth) - put in the non-uri base64-formatted image

https://www.star-m.jp/products/s_print/sdk/react-native-star-io10/manual/en/api-reference/star-xpand-command/printer/image-parameter/constructor.html#star-xpand-command-printer-image-parameter-constructor

lung2008123 avatar Dec 07 '21 04:12 lung2008123

android its not working but works fine on ios any clue if i print it on android app crashes WhatsApp Image 2022-02-18 at 4 41 13 PM

Frankiz123 avatar Feb 18 '22 13:02 Frankiz123

Hi @Frankiz123, can you specify the error you encounter in follow categories:

  1. How that crash happened?
  2. Sample code you're using
  3. Debug logging
  4. Your printer model details

These info are great for others to help in your code. I'm not coding in Android but I'll try to help!

lung2008123 avatar Feb 18 '22 16:02 lung2008123

@lung2008123 check this

async function print(address: string): Promise { // Specify your printer connection settings. // trackMessagesHandler("Start Print Function.");

if (Platform.OS == "android" && 31 <= Platform.Version) {
  if (bluetoothIsEnabled) {
    var hasPermission = await _confirmBluetoothPermission();

    if (!hasPermission) {
      Alert.alert(
        `PERMISSION ERROR: You have to allow Nearby devices to use the Bluetooth printer`
      );
      return;
    }
  }
}

var settings = new StarConnectionSettings();
settings.interfaceType = InterfaceType.Bluetooth;
settings.identifier = address;
var printer = new StarPrinter(settings);
trackMessagesHandler(
  "Printer Start Response. " + JSON.stringify(printer) || "N/A"
);
try {
  // Connect to the printer.
  let tempResponse = await printer.open();
  trackMessagesHandler(
    "Printer Open Response. " + JSON.stringify(tempResponse) || "N/A"
  );
  // capture svg under the reference view
  const bar = await captureRef(foo.current as any, {
    format: "jpg",
    quality: 0.8,
    result: "base64",
    width: pixelWidth,
  })
    .then((base64) => {
      console.log("Image captured and saved as base64:", base64);
      trackMessagesHandler(
        "Image captured and saved as base64: " + base64 || "N/A"
      );
      return base64;
    })
    .catch((error) => {
      console.log(error);
      trackMessagesHandler("Error base46 : " + error || "N/A");
    });

  // create printing data. (Please refer to 'Create Printing data')
  var builder = new StarXpandCommand.StarXpandCommandBuilder();
  trackMessagesHandler("Builder Message : " + builder || "N/A");
  builder.addDocument(
    new StarXpandCommand.DocumentBuilder().addPrinter(
      new StarXpandCommand.PrinterBuilder()
        .actionPrintImage(
          new StarXpandCommand.Printer.ImageParameter(
            bar as string,
            pixelWidth
          )
        )
        .actionCut(StarXpandCommand.Printer.CutType.Partial)
    )
  );

  trackMessagesHandler("2. Builder Message : " + builder || "N/A");
  // ...
  var commands = await builder.getCommands();
  trackMessagesHandler("Commands Message : " + commands || "N/A");
  // Print.
  let printout = await printer.print(commands);
  trackMessagesHandler("PrintOut Message Success : " + printout || "N/A");

  console.log(`Success`);
} catch (error) {
  // Error.
  trackMessagesHandler("PrintOut Error Message Error : " + error || "N/A");
  console.log(error);
} finally {
  // Disconnect from the printer and dispose object.
  await printer.close();
  await printer.dispose();
}

}

const trackMessagesHandler = (message: string) => { setTrackingMessages(message); let message2 = messagesTrackingArray; message2.push(message); setMessagesTrackingArray(message2); };

Frankiz123 avatar Feb 18 '22 18:02 Frankiz123

Hi @Frankiz123, can you specify the error you encounter in follow categories:

  1. How that crash happened?
  2. Sample code you're using
  3. Debug logging
  4. Your printer model details

These info are great for others to help in your code. I'm not coding in Android but I'll try to help!

@lung2008123 this is the printer model Star Micronics TSP143IIIBi.

Frankiz123 avatar Feb 18 '22 18:02 Frankiz123