image icon indicating copy to clipboard operation
image copied to clipboard

copyCrop with same width and size not giving original image

Open tonystark262 opened this issue 4 years ago • 6 comments

If you apply the copyCrop function with starting as 0,0 and width and height of the original image, then you get visually similar images but not exactly the same. img.Image trimmed = img.copyCrop(image, 0, 0, image.width, image.height);

The width and height of the new image are the same which is expected but the size of the image increases from 64KB to 320KB which isn't expected. I get that when you crop the image, size might increase due to encoding not being perfect but it shouldn't happen when our image bounds are the same. The encoding of the input and output images are the same.

I also tried checking every value from a print statement in your function and it seems fine. I am not able to find the bug related to this problem. Maybe it is not a bug and I lack some understanding?

tonystark262 avatar Jun 10 '21 09:06 tonystark262

Finally, I also tried an image comparison tool from https://online-image-comparison.com/ website. Turns out, there are super small differences in the image and I am not sure why are these differences coming.

tonystark262 avatar Jun 10 '21 09:06 tonystark262

By the "size of the image", do you mean the size of an encoded jpeg after resizing it? If so, then the compression level would be responsible for that, not the resize.

brendan-duncan avatar Jun 10 '21 16:06 brendan-duncan

Yes, by size I mean the size of the image or the length of the byte array.

I applied the following code and found out that the problem occurs when I decode and encode the image again. The original image is definitely JPEG.

Uint8List bytes = editedImage.originalFile.readAsBytesSync();

final jpg = img.JpegDecoder();
if (jpg.isValidFile(bytes)) {
    print("Valid jpg original");
}

Uint8List newBytes = img.encodeNamedImage(img.decodeImage(bytes), "randomPath.jpeg");

if (newBytes .length != bytes.length) {
print(
    "length not equal encoded ${newBytes .length} original ${bytes.length}");
}

the length of arrays is not equal. The new image is around 4x the size of the original image. The default value of compression quality is 100%, so this shouldn't be an issue.

tonystark262 avatar Jun 10 '21 17:06 tonystark262

What compression level was the original jpeg saved with? 100%? With a different compression program? Jpeg is a weird format and doesn't explicitly standardize how an image is compressed, so two compressors compressing the same image will generate different resulting images. It's meant to be visibly equivalent, not binary compatible. But that's a large number of bytes to be different, so I suspect different quality settings.

brendan-duncan avatar Jun 10 '21 18:06 brendan-duncan

Maybe you are right. I do not know the original compression level as the images were downloaded from the internet.

Though I am not an expert on JPEG, I do not think what you said is correct as once you encode an image with some compression level, you cannot recover the original. Therefore the original compression of the image should not have any effect. So even if you originally compressed with 60%, then when you read the image back, I think it would be interpreted as 100% only.

But I guess we have no way of knowing as the original compression is not available.

tonystark262 avatar Jun 10 '21 19:06 tonystark262

Jpeg is lossy, every time you decode it and re-encode it, you lose info, and it will never re-encode the same. Also, two compressors newly encoding a raw image, with the same compression level, are not required to have a byte-to-byte equivalency for the compressed image. So no two compressors will encode the same, just similar. I would try using a lower compression level when encoding the jpeg, see if you can get the smaller file size without too much loss of quality.

brendan-duncan avatar Jun 10 '21 19:06 brendan-duncan