Как получить правильный цвет пикселя на изображении [React Native]

#javascript #android #ios #reactjs #react-native

Вопрос:

Я работаю над приложением, которое предназначено для захвата/загрузки изображения, а затем для получения правильного цвета по координате касания на этом изображении / виде камеры. (Аналогично приложению для образцов iOS)

Библиотеки , которые я использую, — это react-native-camera , react-native-get-pixel-color и react-native-draggable .

Есть какая-то логическая проблема, с которой я столкнулся в настоящее время….и я исследовал ее в Интернете и все еще заблудился в джунглях

Соотношение всех устройств не одинаковое, поэтому я не мог жестко указать соотношение, основываясь на документе, в котором указано, что ratio оно доступно только для Android, но не для iOS (по умолчанию для Android будет 4:3, если оно не определено). Поэтому я думаю, не лучше ли его не устанавливать ? Лучше полагаться на размер изображения ? Или может без того и другого ? Любые советы приветствуются…

Часть, которую я сейчас довольно запутываю, связана с вычислением , я хотел получить правильную часть цвета изображения, несмотря на разное соотношение, размер экрана устройства и размер изображения:

  • Прямой просмотр — всегда добирайтесь из центра
  • Все еще вид — на основе перетаскиваемого и получения координат
 renderCamView = () => {
    if (this.state.isEnabled) {
      return (
        <Image
          source={{ uri: this.state.liveImg.data.uri }}
          style={styles.imgPreview}
        />
      );
    } else {
      return (
        <RNCamera
          ref={(ref) => {
            this.camera = ref;
            console.log('isref');
          }}
          onCameraReady={()=> this.getCamData()}
          style={{
    flex: 1,
    justifyContent: 'flex-start',
    alignItems: 'center',
    backgroundColor: colors.black
  }}
          type={RNCamera.Constants.Type.back}
          flashMode={this.getFlashMode()}
          exposure={this.state.camera.exposure}
          whiteBalance={this.state.camera.whiteBalance}
          //ratio={'1:1'}
          // pictureSize={this.state.pictureSize}
          captureAudio={false}
          androidCameraPermissionOptions={{
            title: 'Permission to use camera',
            message: 'We need your permission to use your camera',
            buttonPositive: 'Ok',
            buttonNegative: 'Cancel',
          }}
        />
      );
    }
  };
 
 renderCenterView = () => {

    if(this.state.isEnabled){
      const { liveImg, mainView } = this.state;

      return <Draggable
          x={(this.state.mainView.width/2)-20} y={(this.state.mainView.height/2)-20}
          isCircle
          onShortPressRelease={this.captureColor}
          onDragRelease={this.onDragEvt}
          minX={0}
          minY={0}
          maxX={this.state.mainView.width}
          maxY={this.state.mainView.height}
      >
        <View
            style={{ width:50, height:50,borderWidth:15, borderRadius: 50, borderColor:'#d1c1b6', opacity: 0.8 }}></View>
      </Draggable>
    }else{
      return <TouchableOpacity
          onPress={this.captureColor}
          style={[styles.middlePoint, { top:(this.state.mainView.height/2)-20, left:(this.state.mainView.width/2)-20 }]}/>
    }
  }
 
 // Logic on Draggable, to find the coordinates on image view 
onDragEvt = (event, gestureState, bounds) => {
    let sourceWidth = this.state.liveImg.width;
    let sourceHeight = this.state.liveImg.height;

    // Find view dimensions
    let width = this.state.mainView.width;
    let height = this.state.mainView.height;

    // Assuming image has been scaled to the smaller dimension to fit, calculate the scale
    let wScale = width / sourceWidth;
    let hScale = height / sourceHeight;
    let scale = Math.min(wScale, hScale);

    // Find the offset in the direction the image doesn't fill the screen
    // For ImageViews that wrap the content, both offsets will be 0 so this is redundant
    let offsetX = 0;
    let offsetY = 0;
    if (wScale <= hScale) {
      offsetY = height / 2 - (scale * sourceHeight) / 2;
    } else {
      offsetX = width / 2 - (scale * sourceWidth) / 2;
    }

    // Convert event coordinates to image coordinates
    let sourceX = (gestureState.moveX - offsetX) / scale;
    let sourceY = (gestureState.moveY - offsetY) / scale;

    if (sourceX < 0) {
      sourceX = 0;
    } else if (sourceX > sourceWidth) {
      sourceX = sourceWidth - 5;
    }

    if (sourceY < 0) {
      sourceY = 0;
    } else if (sourceY > sourceHeight) {
      sourceY = sourceHeight - 5;
    }

    this.setState({ dragView: { x: sourceX, y: sourceY } });
  };
 
 getPixelByPercentage(percentage, widthOrHeight) {
    return (percentage / 100) * widthOrHeight;
  }

getPixel(imageData, x, y) {
    try {
      GetPixelColor.setImage(isIOS ? imageData.uri : imageData.base64).catch(
        (err) => {
          // Handle errors
          console.error(err);
        },
      );

      GetPixelColor.pickColorAt(x, y)
        .then((color) => {
          // from react-native-get-pixel-color
          // 'color' return as HEX
        })
        .catch((err) => {
          // Handle errors
          console.error(err);
        });
    } catch (e) {}
  }

captureColor = async () => {
    if (this.state.isEnabled) {
      // live view

      const { dragView, liveImg } = this.state;

      if (Object.keys(dragView).length !== 0) {
        let sourceX = dragView.x;
        let sourceY = dragView.y;

        this.getPixel(liveImg.data, sourceX, sourceY);
      } else {
        let getPiX = this.getPixelByPercentage(50, liveImg.width);
        let getPiY = this.getPixelByPercentage(50, liveImg.height);

        this.getPixel(liveImg.data, getPiX, getPiY);
      }
    } else {
      if (this.camera) {
        const data = await this.camera.takePictureAsync(CAM_OPTIONS);

        await Image.getSize(data.uri, (width, height) => {
          console.log('W: ', width);
          console.log('H: ', height);
          this.setState({
            capImage: {
              data: data,
              imageBase64: data.base64,
              width: width,
              height: height,
            },
          });
        }).then((res) => {
          const { capImage } = this.state;

          let getPiX = this.getPixelByPercentage(50, capImage.width);
          let getPiY = this.getPixelByPercentage(50, capImage.height);

          this.getPixel(capImage.data, getPiX, getPiY);
        });
      }
    }
  };
 

NOTES:

  1. renderCamView() - render either Camera or Image
 2. renderCenterView() - render the center item, either is draggable in 'still' view or fixed touchable button in 'live' view to always get the center point
 3. onDragEvt() - the Draggable's event to keep track the draggable item's movement
 4. this.state.mainView - the state that holds width and height of the root <View /> of this screen
 5. captureColor() - onPress event to get the pixel color
 6. this.state.isEnabled - define it is still view / live view

 

Live view — (Camera view)

Still view — (Capture and display as image / image select from album)

*Sorry for my bad English, if there is any confusing part please let me know