callstack / react-native-image-editor

A library providing an API for cropping images from the web and the local file system.
MIT License
376 stars 118 forks source link

Output size of ImageEditor.cropImage is incorrect #27

Closed jayu closed 4 years ago

jayu commented 5 years ago

This issue is moved from react-native repo because the image editor was extracted. See original issue [#22941].

Issue Content

Environment

React Native Environment Info: System: OS: Windows 10 CPU: (4) x64 Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz Memory: 1.68 GB / 7.91 GB Binaries: Yarn: 1.9.4 - ~\AppData\Roaming\npm\yarn.CMD npm: 6.5.0 - ~\AppData\Roaming\npm\npm.CMD IDEs: Android Studio: Version 3.2.0.0 AI-181.5540.7.32.5056338

Description

Occasionally, output of ImageEditor.cropImage is different from displaySize in cropData, for example setting displaySize to {width: 16, height: 16} will output size {width: 15, height: 15} or {width: 16, height: 16}

Reproducible Demo

Put the code below somewhere in the entry file, or use this snack

import { Image, ImageEditor } from "react-native";

// promisify functions
function cropImage(uri, cropData) {
  return new Promise((resolve, reject) =>
    ImageEditor.cropImage(uri, cropData, resolve, reject)
  );
}
function getSize(uri) {
  return new Promise((resolve, reject) =>
    Image.getSize(uri, (w, h) => resolve({ width: w, height: h }), reject)
  );
}

const width = 2160;
const height = 3840;
const displaySize = { width: 16, height: 16 };

// get a random pic of size 2160x3840
cropImage(`https://source.unsplash.com/random/${width}x${height}`, {
  offset: { x: 0, y: 0 },
  size: { width, height },
  displaySize,
  resizeMode: "cover",
})
  .then(resizedUri => getSize(resizedUri))
  .then(resizedDimensions => console.log(resizedDimensions));

// output:
// Object {
//   "height": 15,
//   "width": 15,
// }

// Expected output:
// Object {
//   "height": 16,
//   "width": 16,
// }

Conversation

@nrator :

After digging into the Android implementation, I believe the bug may be caused by using Math.floor instead of Math.round in these two lines of codes.

int cropWidth = (int) Math.floor(newWidth / (float) outOptions.inSampleSize);
int cropHeight = (int) Math.floor(newHeight / (float) outOptions.inSampleSize);

Since I am not a java developer and I am not familiar with the APIs, e.g. createBitmap, decodeStream, etc, I wish there is someone with more experience could help. Thanks!

@eXist-FraGGer:

@nrator Maybe you have an incorrect result because Image.getSize changed? Try to use this library: react-native-image-size

@mcgloneleviROOT:

A teammate and I ran into a similar issue in our application. After a few hours of debugging, it looks like the image's size returned from Image.getSize is half the size for some reason. For example, we had a ~4000x3000 px image taken from an iPhone. Image.getSize would return 2000x1500. Scaling the value returned from the function by 2 fixed our problem.