andresperezmelo / print_bluetooth_thermal

Plugin para enviar bytes sin procesar a la impresora solo por ahora para Android
Other
27 stars 36 forks source link

Error inserting white space when printing image #20

Closed BrianTV98 closed 1 year ago

BrianTV98 commented 1 year ago

I downloaded the sample project and printed it with the XT 423(DOA) bluetooth printer. For text printing and barcode printing works well. However, in the case of printing photos, there is an error. When debugging, I discovered that for every line (pice) cut from the image, the library automatically inserts a blank line. How to fix this? a5825916e7c633986ad7

andresperezmelo commented 1 year ago

That is a problem of the printing speed of the printer is very low, so that it works in that printer must lower the quality of the image so that the printer can print the logo, in line 340 of the sample project there is an example code how you can reduce the quality of the image, by default is disabled.

if (Platform.isIOS) {
      // Resizes the image to half its original size and reduces the quality to 80%
      final resizedImage = img.copyResize(image!, width: image.width ~/ 1.3, height: image.height ~/ 1.3, interpolation: img.Interpolation.nearest);
      final bytesimg = Uint8List.fromList(img.encodeJpg(resizedImage));
      //image = img.decodeImage(bytesimg);
    }

You can change that code to

if (Platform.isIOS || Platform.isAndroid) {
      // Resizes the image to half its original size and reduces the quality to 80%
      final resizedImage = img.copyResize(image!, width: image.width ~/ 1.3, height: image.height ~/ 1.3, interpolation: img.Interpolation.nearest);
      final bytesimg = Uint8List.fromList(img.encodeJpg(resizedImage));
      image = img.decodeImage(bytesimg);
    }

This will lower the quality of the logo so that the printer is able to print the logo before moving on to the next line.

BrianTV98 commented 1 year ago

Thanks for the very quick response. However, reducing the size of the image is unacceptable. That is not true to the printer's original desire to print invoices.

BrianTV98 commented 1 year ago

I tried to find another solution. The first step was successful. However, this is only a temporary solution. I would like to share here the direction of reasoning and solution.

  1. First, to lose the white line I used the isDoubleDensity = false property. This made the image seamlessly printable. However. If an image is too long, it will not be possible to print it all. After a period of debugging, I thought that iOS was sending data too quickly, leading to a blockage in the printer queue. All data that exceeds the batch will be discarded.

To prove it. I cut an image into equal parts with a height of 276. Then I printed the images one at a time. After each writeData I delayed 750 ms. (Can only be done with images with with >= 567).

It finally worked.

And here is the sample code.

static Future<bool> printImage(Image image, String printAddress)async{

      image = copyResize(image, width: 567, interpolation: Interpolation.cubic);
      int offset = 0;
      int pieceCount =  (image.height~/ 276).ceil();
      bool isSuccess = true;
      if(Platform.isAndroid){
        final profile = await CapabilityProfile.load();
        final generator = Generator(PaperSize.mm80, profile);
        List<int> bytes = [];
        bytes += generator.image(
            image,
            isDoubleDensity: false,
            align: PosAlign.left
        );

        bool connectionStatus = await PrintBluetoothThermal.connectionStatus;

        if (!connectionStatus) await PrintBluetoothThermal.connect(macPrinterAddress: printAddress);

        var result = await PrintBluetoothThermal.writeBytes(bytes);

        return result ;
      }
      for(int i =1; i<=pieceCount; i++){
        var tmp = copyCrop(image,x: 0, y: offset, width: image.width, height: 276);
        offset += 276;
        List<int> bytes = [];
        // Using default profile
        final profile = await CapabilityProfile.load();
        final generator = Generator(PaperSize.mm80, profile);

        bytes += generator.image(
            tmp,
            isDoubleDensity: false,
            align: PosAlign.left
        );
        bool connectionStatus = await PrintBluetoothThermal.connectionStatus;

        if (!connectionStatus) await PrintBluetoothThermal.connect(macPrinterAddress: printAddress);

        var result = await PrintBluetoothThermal.writeBytes(bytes);

        if(!result) isSuccess = false;

        await Future.delayed(const Duration(milliseconds: 750));
      }
      return isSuccess;
  }

This idea only works on ios. As for Android, everything works fine. We cannot apply this method to Android because after each photo printing. it will automatically insert feed(1) right after. So we separated it into 2 independent cases for Android and iOS

BrianTV98 commented 1 year ago

We tried a few other methods to solve the problem after performing step 1. For example: Increase chunk of ios from 150 -> 200. It worked, however the printer prints photos very slowly after doing this.

andresperezmelo commented 1 year ago

Thank you for sharing your experience