brendan-duncan / image

Dart Image Library for opening, manipulating, and saving various different image file formats.
MIT License
1.18k stars 266 forks source link

Different output between v3 and v4 #452

Open dishuostec opened 1 year ago

dishuostec commented 1 year ago

I have a png file optimized via https://tinypng.com. When I use copyResize with different interpolation, the output file is very different between v3 and v4.

Source file:

Output:

image

I created a reproduction repo.

brendan-duncan commented 1 year ago

The image is a paletted image, so the interpolation modes aren't correct for that. It would have to be converted to an 32-bit RGBA image first, via final rgbaImage = image.convert(numChannels: 4);.

V3 didn't support paletted images, so all images were 32-bit RGBA.

Since copyResize always returns a new image, I'll have it auto-convert the image if you use non-nearest interpolation.

brendan-duncan commented 1 year ago

I pushed the update to github, to auto convert images for transform functions that use non-nearest interpolation. I'll be doing a publish soon.

If you want to convert it back to a palette image, you can use the quantize or ditherImage functions.

luciano-cervantes commented 1 year ago

I'm having a similar problem. I have an image in QR Code that I send in bytes to a printer via the serial port, using the package in version 3 it was working but now it comes out all wrong. see photo below.

Future<void> image(Image src) async {
    final Image image = Image.from(src); // make a copy
    const bool highDensityVertical = true;

    invert(image);

    flip(image, direction: FlipDirection.horizontal);
    final Image imageRotated = copyRotate(image, angle: 270);

    const int lineHeight = highDensityVertical ? 3 : 1;
    final List<List<int>> blobs = _toColumnFormat(imageRotated, lineHeight * 8);
}

/// Extract slices of an image as equal-sized blobs of column-format data.
  ///
  /// [image] Image to extract from
  /// [lineHeight] Printed line height in dots
  List<List<int>> _toColumnFormat(Image imgSrc, int lineHeight) {
    final Image image = Image.from(imgSrc); // make a copy

    // Determine new width: closest integer that is divisible by lineHeight
    final int widthPx = (image.width + lineHeight) - (image.width % lineHeight);
    final int heightPx = image.height;

    // Create a black bottom layer
    final biggerImage = copyResize(image, width: widthPx, height: heightPx);
    fill(biggerImage, color: ColorRgb8(0, 0, 0));
    // Insert source image into bigger one
    compositeImage(biggerImage, image, dstX: 0, dstY: 0);

    int left = 0;
    final List<List<int>> blobs = [];

    while (left < widthPx) {
      final Image slice = copyCrop(biggerImage, x: left, y: 0, width: lineHeight, height: heightPx);
      final Uint8List bytes = slice.getBytes();
      blobs.add(bytes);
      left += lineHeight;
    }

    return blobs;
  }

image

brendan-duncan commented 1 year ago

Most likely it's because in v3 all images are RGBA 32-bit, and in v4 it supports a lot of different image formats. Your blobs output probably assumes the old RGBA 32-bit data, and the image you loaded probably is not that. So you should convert the image first:

final Image slice = copyCrop(biggerImage, x: left, y: 0, width: lineHeight, height: heightPx);
final sliceRgba32 = slice.convert(format: Format.uint8, numChannels: 4);
final Uint8List bytes = sliceRgba32.getBytes();
blobs.add(bytes);
left += lineHeight;
luciano-cervantes commented 1 year ago

Let's just say it didn't work out very well.

image