VGamezz19 / react-native-sketch-draw

🔵React Native (v0.53) 🎨Component for touch based drawing supporting iOS and Android.
MIT License
34 stars 9 forks source link

Images sent in 'localSourceImagePath' prop, are shown with zoom #2

Open diego-caceres opened 6 years ago

diego-caceres commented 6 years ago

When I take a picture using react-native-camera, save it in Capture Mode 'temp' and then pass this down as a prop (previously removing the 'file://' from the path), when SketchDraw is shown, shows the image with zoom, so it's different from the picture taken by the user.

Any help is appreciated. Thanks

Some screenshots to showcase this case: screenshot_20180411-164241 screenshot_20180411-164304

Environment

Environment: OS: macOS Sierra 10.12.6 Node: 8.4.0 Yarn: 0.27.5 npm: 5.4.0 Watchman: 4.7.0 Xcode: Xcode 8.3.3 Build version 8E3004b Android Studio: 2.3 AI-162.4069837

Packages: (wanted => installed) react-native: 0.48.1 => 0.48.1 react: 16.0.0-alpha.12 => 16.0.0-alpha.12

diego-caceres commented 6 years ago

I created a new project from scratch using the RN version 0.53, but this issue is still there, there's a lot of zoom added to picture used as 'localSourceImagePath', in my case It always happends with the top left corner.

This is the updated Environment info: Environment: OS: macOS High Sierra 10.13.4 Node: 6.11.1 Yarn: 1.3.2 npm: 5.6.0 Watchman: 4.7.0 Xcode: Xcode 9.2 Build version 9C40b Android Studio: 2.3 AI-162.3764568

Packages: (wanted => installed) react: 16.2.0 => 16.2.0 react-native: 0.53.0 => 0.53.0

Thanks

diego-caceres commented 6 years ago

If you need a code snippet, this is my App so far to test this:

import React, { Component } from 'react';
import {
  Platform,
  StyleSheet,
  Text,
  View,
  Button,
  Alert,
  Image,
  TouchableHighlight
} from 'react-native';
import Camera from "react-native-camera";
import SketchDraw from 'react-native-sketch-draw';

const SketchDrawConstants = SketchDraw.constants;

const tools = {};

tools[SketchDrawConstants.toolType.pen.id] = {
    id: SketchDrawConstants.toolType.pen.id,
    name: SketchDrawConstants.toolType.pen.name,
    nextId: SketchDrawConstants.toolType.eraser.id
};
tools[SketchDrawConstants.toolType.eraser.id] = {
    id: SketchDrawConstants.toolType.eraser.id,
    name: SketchDrawConstants.toolType.eraser.name,
    nextId: SketchDrawConstants.toolType.pen.id
};

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      openCamera: false,
      photoPath: '',
      toolSelected: SketchDrawConstants.toolType.pen.id,
      color: '#FFFFFF',
      photo2Path: ''
    };
  }
  takePicture() {
    const options = {};
    this.camera
      .capture({ metadata: options })
      .then(data => {
        console.log(data);
        this.setState({ openCamera: false, photoPath: data.path.replace("file://", "") });
        Alert.alert("Photo saved!");
      })
      .catch(err => console.error(err));
  }
  isEraserToolSelected() {
    return this.state.toolSelected === SketchDrawConstants.toolType.eraser.id;
  }

  toolChangeClick() {
      this.setState({toolSelected: tools[this.state.toolSelected].nextId});
  }

  getToolName() {
      return tools[this.state.toolSelected].name;
  }

  onSketchSave(saveEvent) {
      this.props.onSave && this.props.onSave(saveEvent);
      console.log('Saved:',saveEvent.localFilePath);
      debugger;
      this.setState({ 
        photo2Path: 'file://' + saveEvent.localFilePath
      })
  }
  render() {
    if(this.state.photo2Path.length > 0) {
      return (
        <View style={{flex: 1}}>
          <Image
          source={{uri: this.state.photo2Path, isStatic:true}}
          style={{flex:1}}
          />
        </View>
      )
    }

    if(this.state.photoPath.length > 0) {
      return (
        <View style={{flex: 1}}>
          <View style={{flex: 1, flexDirection: 'column'}}>
            <SketchDraw style={{flex: 1, backgroundColor: 'white'}} ref="sketchRef" 
            selectedTool={this.state.toolSelected} 
            toolColor={this.state.color} //Yelow Example! you can changIT!
            onSaveSketch={this.onSketchSave.bind(this)}
            localSourceImagePath={this.state.photoPath}/>
            <View style={{ flexDirection: 'row', backgroundColor: '#EEE'}}>
              <TouchableHighlight underlayColor={"#CCC"} style={{ flex: 1, alignItems: 'center', paddingVertical:20 }} 
                onPress={() => { 
                  this.setState({
                    color: '#FFFFFF'
                  }) 
                }}>
                <Text style={{color:'#888',fontWeight:'600'}}>WHITE</Text>
              </TouchableHighlight>
              <TouchableHighlight underlayColor={"#CCC"} style={{ flex: 1, alignItems: 'center', paddingVertical:20 }} 
                onPress={() => { 
                  this.setState({
                    color: '#FFFA38'
                  }) 
                }}>
                <Text style={{color:'#FFFA38',fontWeight:'600'}}>YELLOW</Text>
              </TouchableHighlight>
              <TouchableHighlight underlayColor={"#CCC"} style={{ flex: 1, alignItems: 'center', paddingVertical:20 }} 
                onPress={() => { 
                  this.setState({
                    color: '#EE5458'
                  }) 
                }}>
                <Text style={{color:'#EE5458',fontWeight:'600'}}>RED</Text>
              </TouchableHighlight>
              <TouchableHighlight underlayColor={"#CCC"} style={{ flex: 1, alignItems: 'center', paddingVertical:20 }} 
                onPress={() => { 
                  this.setState({
                    color: '#6CBF5A'
                  }) 
                }}>
                <Text style={{color:'#6CBF5A',fontWeight:'600'}}>GREEN</Text>
              </TouchableHighlight>
            </View>
            <View style={{ flexDirection: 'row', backgroundColor: '#EEE'}}>
                <TouchableHighlight underlayColor={"#CCC"} style={{ flex: 1, alignItems: 'center', paddingVertical:20 }} onPress={() => { this.refs.sketchRef.clearSketch() }}>
                  <Text style={{color:'#888',fontWeight:'600'}}>CLEAR</Text>
                </TouchableHighlight>
                <TouchableHighlight underlayColor={"#CCC"} style={{ flex: 1, alignItems: 'center', paddingVertical:20, borderLeftWidth:1, borderRightWidth:1, borderColor:'#DDD' }} onPress={() => { this.refs.sketchRef.saveSketch() }}>
                  <Text style={{color:'#888',fontWeight:'600'}}>SAVE</Text>
                </TouchableHighlight>
                <TouchableHighlight underlayColor={"#CCC"} style={{ flex: 1, justifyContent:'center', alignItems: 'center', backgroundColor:this.isEraserToolSelected() ? "#CCC" : "rgba(0,0,0,0)" }} onPress={this.toolChangeClick.bind(this)}>
                  <Text style={{color:'#888',fontWeight:'600'}}>ERASER</Text>
                </TouchableHighlight>
            </View>
          </View>
        </View>
      )
    }

    return (
      <View style={styles.container}>
        {this.state.openCamera
          ? <Camera
              ref={cam => {
                this.camera = cam;
              }}
              style={styles.preview}
              captureTarget={Camera.constants.CaptureTarget.temp}
              aspect={Camera.constants.Aspect.fill}
            >
              <Text
                style={styles.capture}
                onPress={this.takePicture.bind(this)}
              >
                [Take Photo]
              </Text>
            </Camera>
          : <View>
            <Button
              title="Open Camera"
              onPress={() => this.setState({ openCamera: true })}
            />

          </View>
          }

      </View>
    );
  }
}

// <Image
//                 source={{uri: this.state.photoPath, isStatic:true}}
//                 style={{width: 300, height: 300}}
//                 />

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center"
  },
  preview: {
    flex: 1,
    justifyContent: "flex-end",
    alignItems: "center"
  },
  capture: {
    backgroundColor: "#fff",
    borderRadius: 5,
    color: "#000",
    padding: 10,
    margin: 40
  }
});
mark-spurgeon commented 6 years ago

Hi, I ran into an issue that might be linked to the same thing. The issue was that the drawing area was, sometimes, much bigger than what was instructed in the stylesheet (basically, the sketching area is inconsistent, it might be bigger than the screen).

You can create a view in which there is the camera's image and, in a separate view, the sketch area (with a transparent background). Then, to output a consistent sketch, you can use react-native's ImageEditor.cropImage(imagepath, {offset:{x:0,y:0},size:{width:300,height:300}}, (success)=>{console.warn(success)}, (error)=>{console.error(error)} ) (documentation is poor so I put the whole thing) to correct the image output. You can get the width and height by adding an onLoad event to the view (if you don't know the view's fixed size), saving them as state values. And converting these to pixels with react-native's PixelRatio.getPixelSizeForLayoutSize(<width>).

Hope it helps, though it may not be the same issue.

TimMun commented 6 years ago

I'm running into the same issue... While the workaround above works for saving an image, it doesn't help much if you want to use the localSourceImagePath prop.

The root issue is that the sketch area thinks it's a lot bigger than it actually is; on iPhone 6, when it happens the sketch area is 2x the height and 2x the width as whatever the view is supposed to be. When a localSourceImagePath is specified, it takes up the whole UIView area and so you only see the top left quarter of the image in the RN View.

The only thing I can think of that might explain the 2:1 ratio above might be some kind of point to pixel mixup. But it's also very strange that this only happens sometimes, for me maybe 30% of the time.

TimMun commented 6 years ago

After further digging it's almost certainly related to this issue

cristianoccazinsp commented 5 years ago

Did you ever solve this issue? @TimMun

cristianoccazinsp commented 5 years ago

Update for anyone struggling with this, very hackish way to "fix it".

1) Process the original image with react-native-image-resizer. Create a thumbnail as follows.

let maxSize = Math.max(this.props.orientation.width, this.props.orientation.height);
maxSize = PixelRatio.getPixelSizeForLayoutSize(maxSize);

let thumbData = await ImageResizer.createResizedImage(
  this.props.item.uri,
  maxSize,
  maxSize,
  'JPEG',
  100
);

Note: replace props with w/e you are using to get screen width and height

2) Use this thumbnail for the sketch component. Note that the final image proportions will change a bit due to how the resizing works. Also, don't forget to cleanup the image on component unmount.

3) Still trying to fine tune this to make the image look better.

TimMun commented 5 years ago

This was a long time ago so I can't remember exactly what the details of the problem were. But it looks like I fixed it in my fork of the repo...

https://github.com/TimMun/react-native-sketch-draw/commit/76ad3ce38d91e4a3633901ebe6ae1ce34a8dc299

I'm using that in conjunction with the-duck's solution mentioned above.

cristianoccazinsp commented 5 years ago

@TimMun interesting. Did you only fix it for iOS? Because I saw the issue happening on Android as well, and so far, only building an exact thumbnail image of the original one worked for me.

TimMun commented 5 years ago

I didn't fix for Android, it was one of those todo's that I never got around to

cristianoccazinsp commented 5 years ago

I see, any chance you can push that change as a pull request? I might tackle the android issue myself but I'm curious what was the actual fix for IOS.

TimMun commented 5 years ago

I didn't open one at the time and still don't think its a good idea because I'm not entirely sure why the fix works, and it was more of a hack than anything. (Plus Android wasn't even done yet)

cristianoccazinsp commented 5 years ago

Alright, wish I could get some more ideas. Guess that it is still a good idea to use a resized image as I did so a large image is not loaded into memory... but who knows.