react-native 画一画和保存为图片分享及保存。

上官羽
2023-12-01

本文主要使用知识webview和rn通讯;html 中的canvas画布保存为base64地址回掉给rn;
本篇为本人亲自写的一个项目活动,现在分享给大家;

1.ValentinesDay.js 文件
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */
import React, { Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    TouchableOpacity, Image, Dimensions,
    View, ScrollView, TouchableWithoutFeedback
} from 'react-native';
import WebCanvas from './webCanvasss';     //引入  webview中html的代码
import { cal } from './../Common/Cal.js';  //我自己封装的适配,你们可以把下面的cal()都去掉看效果
const base64= 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA。。。。。'; // 随便写个base64地址,
const url = 'http://192.168.0.43:8080/teacher/data/01010072/1/438/4257-1-0-0.jpg';
const BACKGROUND = require('../image/activity/background.png');//这些图片是我本地的,复制代码时候,随便用你自己本地图片代替,这样避免报错
const CANVASIMAGE = require('../image/activity/canvas.png');
const BI = require('../image/activity/pen.png');
const BIED = require('../image/activity/ penEd.png');
const CA = require('../image/activity/grater.png');
const CAED = require('../image/activity/ graterEd.png');
const BTN = require('../image/activity/btn.png');
const MODALCANVAS = require('../image/activity/activeModal.png');
const { width, height } = Dimensions.get("window");
import ValentinesDaySub from "./ValentinesDaySub";//跳到下一个页面
export default class ValentinesDay extends Component {
    constructor(props) {
        super(props);
        SplashScreen.hide();
        this.state = {
            scrollEnabled: true,  //判断画笔和橡皮擦
            modal: false
        }
    }
    _pen() {
        this.setState({
            scrollEnabled: true
        })
        this.refs.canvas._pen();
    }
    _clean() {
        this.setState({
            scrollEnabled: false
        })
        this.refs.canvas._clean();
    }
    // 以url的形式添加背景
    _addImageUrl() {
        this.refs.canvas._addImageUrl(url);
    }
    // 以base64的形式添加背景
    _addImageBase64() {
        this.refs.canvas._addImageBase64(base64);
    }
    // 得到图片的base64形式
    _getBase64() {
        this.refs.canvas._getBase64(base64);
    }
    // 保存base64
    _handleBase64(data) {
        // console.log(data)
        this.props.navigator.push({
            component: ValentinesDaySub,
            params: {
                navigator: this.props.navigator,
                canvasUrl: data,
                new:this.props.new
            }
        })
    }
    // 图片右转
    _rotateRight() {
        this.refs.canvas._rotateRight();
    }
    _Modal() {
        if(!this.state.modal) return false;
        return (
            <View style={styles.ModalBackground}>
                <Image
                    source={MODALCANVAS}
                    style={{
                        width: cal(343),
                        height: cal(496),
                        resizeMode: 'cover',
                        marginTop: cal(-30),
                        justifyContent: "flex-end",
                        alignItems: "center"
                    }}
                >
                    <View style={{
                        width: cal(303),
                        height: cal(350), marginBottom: cal(30)
                    }}>
                        <Text style={{ fontSize:cal(13), color:"#202020",marginBottom:cal(9),lineHeight:18}}>1. 活动时间:<Text style={{ color:"#f84e48" }}>2018年2月14日—2018年2月21日</Text>。</Text>
                        <Text style={{ fontSize:cal(13), color:"#202020",marginBottom:cal(9),lineHeight:18}}>2. 活动玩法:用户在指定区域勾勒任意图像,然后会随机生成一支签。没有上上签,也没有下下签,只有几句有意思的新年寄语。(ps:新用户参与活动后,需继续完成<Text style={{ color:"#f84e48" }}>注册</Text>获得中奖资格)。 </Text>
                        <Text style={{ fontSize:cal(13), color:"#202020",marginBottom:cal(9),lineHeight:18}}>3. 活动奖励:我们会在所有参与活动的新老注册用户中随机抽取,每位用户可不限次数画图抽签(你可以刷爆我们的图库,只为你满意的那根签),不过不会增加中奖概率。</Text>
                        <Text style={{ fontSize:cal(13), color:"#202020",marginBottom:cal(9),lineHeight:18}}>4. 奖品:一等奖:价值<Text style={{ color:"#f84e48" }}>4000元</Text>的单人或双人游   二等奖: <Text style={{ color:"#f84e48" }}>200元</Text>红包    三等奖:<Text style={{ color:"#f84e48" }}>66元</Text>红包  (各档中奖人数视活动人数而定)。</Text>
                        <Text style={{ fontSize:cal(13), color:"#202020",marginBottom:cal(9),lineHeight:18}}>5. 获奖名单将于活动结束<Text style={{ color:"#f84e48" }}>三天内</Text>,在app中公布,而奖品会在工作人员与获奖者核实信息后的<Text style={{ color:"#f84e48" }}>五个工作日</Text>内寄出。</Text>
                        <Text style={{ fontSize:cal(13), color:"#202020",marginBottom:cal(9),lineHeight:18}}>6. 本活动最终解释权归爱特缘所有。</Text>
                    </View>
                    <TouchableOpacity
                        onPress={() => {
                            this.setState({
                                modal :false
                            })
                        }}
                        style={{
                            position: "absolute", width: cal(50),
                            height: cal(50),  right: 0, top: cal(-1)
                        }}>
                        <Text></Text>
                    </TouchableOpacity>
                </Image>
            </View>
        )
    }
    render() {
        return (
            <View style={styles.container}>
             //   <Header type={"zhuce"} title={"一画“签”金"} {... this.props} />
                {this._Modal()}
                <Image source={BACKGROUND} style={styles.imagecontainer}>
                    <View style={styles.canvasViewImage}>
                        <Image source={CANVASIMAGE} style={styles.canvasImage} >
                            <View style={styles.canvasStart}>
                                <WebCanvas
                                    handleBase64={this._handleBase64.bind(this)}
                                    ref='canvas'
                                    width={cal(250)}
                                    height={cal(280)}
                                />
                            </View>
                            <View style={{ position: "absolute", bottom: cal(20), right: cal(50), flexDirection: "row" }}>
                                <TouchableOpacity onPress={this._pen.bind(this)}>
                                    <Image source={this.state.scrollEnabled ? BIED : BI} style={{ width: cal(27), height: cal(23) }} />
                                </TouchableOpacity>
                                <TouchableOpacity style={{ marginLeft: cal(40) }} onPress={this._clean.bind(this)}>
                                    <Image source={this.state.scrollEnabled ? CA : CAED} style={{ width: cal(27), height: cal(23) }} />
                                </TouchableOpacity>
                            </View>
                        </Image>
                    </View>
                    <View>
                        <View style={styles.btnView}>
                            <TouchableOpacity onPress={this._getBase64.bind(this)} style={styles.btnTouchableOpacity}>
                                <Image source={BTN} style={{ width: cal(150), height: cal(52) }} />
                            </TouchableOpacity>
                        </View>
                        <View style={styles.activityRules}>
                            <TouchableOpacity onPress={()=>{
                                this.setState({
                                    modal:true
                                })
                            }}>
                                <View style={styles.activityRulesView}>
                                    <Text style={styles.activityRulesTextH1}>查看活动规则</Text>
                                </View>
                            </TouchableOpacity>
                        </View>
                    </View>
                    {/* <TouchableOpacity onPress={this._rotateRight.bind(this)}>
            <Text>右转</Text>
            </TouchableOpacity>
            <TouchableOpacity onPress={this._addImageUrl.bind(this)}>
            <Text>url上传</Text>
            </TouchableOpacity>
            <TouchableOpacity onPress={this._addImageBase64.bind(this)}>
            <Text>Base64上传</Text>
            </TouchableOpacity>
            <TouchableOpacity onPress={this._getBase64.bind(this)}>
            <Text>保存图片</Text>
            </TouchableOpacity>
            <Image
            style={{ width:100,height:100 }}
            source={{uri: this.state.imageData, scale: 3}}
        /> */}
                </Image>
            </View>
        );
    }
}
const styles = StyleSheet.create({
    imagecontainer: {
        width: width,
        height: height,
        resizeMode: 'cover',
        // height: cal(603),
        flex: 1
    },
    container: {
        // justifyContent: 'center',
        // alignItems: 'center',
        flex: 1,
        backgroundColor: '#F5FCFF',
    },
    canvasViewImage: {
        alignItems: "center",
        marginTop: cal(50)
    },
    canvasImage: {
        width: cal(317),
        height: cal(390),
        // justifyContent:"center",
        alignItems: "center",
        paddingTop: cal(75),
    },
    canvasStart: {
        width: cal(250),
        height: cal(280),
        backgroundColor: "rgba(0,0,0,0)",
    },
    btnView: {
        alignItems: "center",
        marginTop: cal(15)
    },
    btnTouchableOpacity: {
        width: cal(150),
        height: cal(52)
    },
    activityRules: {
        marginTop: cal(15),
    },
    activityRulesView: {
        alignItems: "center"
    },
    activityRulesTextH1: {
        color: "#b40e12",
        fontSize: cal(16)
    },
    ModalBackground: {
        width: width,
        height: height,
        position: "absolute",
        top: 0,
        left: 0,
        backgroundColor: "rgba(0,0,0,0.7)",
        zIndex: 99,
        justifyContent: "center",
        alignItems: "center"
    },
});

2.           webCanvasss.js
/**
* Created by liudawei on 2017/8/2.
* 基于webview的Canvas画布
*/
import React , { Component } from 'react' ;
import {
  StyleSheet ,
  View ,
  Text ,
  WebView ,
  TouchableOpacity
} from 'react-native' ;
var html =
`<html>
<head>
  <title>canvas</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="http://www.jq22.com/jquery/jquery-1.10.2.js"></script>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
  </style>
</head>
<body>
  <canvas id='can' style='background: rgba(255,255,155,0); position: absolute; z-index: 1'>
    您的浏览器不支持canvas
  </canvas>
  <script>
    var $can = $('#can'),isclean=false,drawState=false,lastX,lastY,ctx;
    var _width,_height;
    window.document.addEventListener('message', function (e){
        var obj = JSON.parse(e.data);
        switch (parseInt(obj.action)){
          case 1:
              /* 铅笔 */
              isclean=false;
              break;
          case 2:
              /* 橡皮 */
              isclean=true;
              break;
          case 3:
              /* 右转 */
              rotateRight();
              break;
          case 4:
              /* url */
              createImg(obj.data);
              break;
          case 5:
              /* case64 */
              createImg(obj.data);
              break;
          case 0:
              /* 返回base64 */
              returnBase64();
              break;
          case -1:
              /* 初始化画板 */
              ctx.clearRect(0,0, _width, _height);
              break;
        }
    });

    function init_canvas(width,height){
      _width = width;
      _height = height;
      $can.attr('width', width);
      $can.attr('height', height);
      ctx = $can[0].getContext("2d");
      registDraw();
    }


    function registDraw(){
        var ox;
        var oy;
        var ox2;
        var oy2;
        $can.on("touchstart", function (e){
            e = e.originalEvent.touches[0];
            ox2 = e.screenX;
            oy2 = e.screenY;
            drawState = true;
            drawState = true;
            var x = e.clientX -  $can.offset().left;
            var y = e.clientY -  $can.offset().top + $(document).scrollTop();
            lastX = x;
            lastY = y;
            draw(x, y, true, isclean);
            return false;
        });
        $can.on("touchmove", function (ev){
            e = ev.originalEvent.touches[0];
            if (drawState){
                if (lastX == null || lastY == null ){
                    $can.lastX = $can.lastY = null;
                    lastX = e.clientX - $can.offset().left;
                    lastY = e.clientY - $can.offset().top + $(document).scrollTop();
                }
                draw(e.clientX - $can.offset().left,
                    e.clientY - $can.offset().top + $(document).scrollTop(),true,isclean);
                return false;
            }
            return false;
        });
        $(document).on("touchend", function (e){
            drawState = false;
        });
    };

    function draw(x, y, isDown, isclean){
        if (isDown) {
            ctx.globalCompositeOperation = isclean ? "destination-out" : "source-over";
            ctx.beginPath();
            ctx.strokeStyle = '#fed935';
            ctx.lineWidth = isclean ? 30 : 5;
            ctx.lineJoin = "round";
            ctx.moveTo(lastX, lastY);
            ctx.lineTo(x, y);
            ctx.closePath();
            ctx.stroke();
        }
        lastX = x;
        lastY = y;
    };

    /* 旋转 */
    function rotateRight(){
        var obj = ctx.getImageData(0,0,_width, _height);
        var new_obj = ctx.createImageData(obj.height, obj.width);
        var num = 0;
        for (var j=0;j<obj.width;j++){
            for (var i=obj.height;i>0;i--){
                new_obj.data[num++] = obj.data[(j + obj.width*(i-1))*4];
                new_obj.data[num++] = obj.data[(j + obj.width*(i-1))*4+1];
                new_obj.data[num++] = obj.data[(j + obj.width*(i-1))*4+2];
                new_obj.data[num++] = obj.data[(j + obj.width*(i-1))*4+3];
            }
        }
        _width = new_obj.width;
        _height = new_obj.height;
        $can.attr("width", this.width);
        $can.attr("height",this.height);
        ctx.clearRect(0,0,this.width,this.height); 
        ctx.putImageData(new_obj, 0, 0);
    };

    function createImg(data){
      var img = new Image();
      img.crossOrigin = '*';
      img.onload = function (){
        var width = img.naturalWidth;
        var height = img.naturalHeight;
        can = $can[0];
        ctx = can.getContext("2d");
        ctx.drawImage(img, 0, 0, _width, _height);
      };
      $(img).attr('src', data);
    }

    function imageData2base64(imgdata){
var can = $("<canvas>").attr("width", imgdata.width).attr("height", imgdata.height);
        can = can[0];
        var ctx = can.getContext("2d");
        ctx.putImageData(imgdata, 0, 0);
        return can.toDataURL();
    }

    /*
        保存图片功能,将图片保存成一张图片并返回base64
    */
    function saveAsBase64(){
        var obj = this.ctx_img.getImageData(0,0,this.width, this.height);
        var obj2 = this.ctx_edit.getImageData(0,0,this.width, this.height);
        var new_obj = this.ctx_img.createImageData(this.width, this.height);
        var len = obj2.data.length / 4;
        for(var i=0;i<len;i++){
            if (obj2.data[i*4+3] != 0){
                new_obj.data[i*4] = obj2.data[i*4];
                new_obj.data[i*4+1] = obj2.data[i*4+1];
                new_obj.data[i*4+2] = obj2.data[i*4+2];
                new_obj.data[i*4+3] = 255;
            }else{
                new_obj.data[i*4] = obj.data[i*4];
                new_obj.data[i*4+1] = obj.data[i*4+1];
                new_obj.data[i*4+2] = obj.data[i*4+2];
                new_obj.data[i*4+3] = obj.data[i*4+3];
            }
        }
        return imageData2base64(new_obj);
    }


    /* 将图片处理成base64返回 */
    function returnBase64(){
      var data = $can[0].toDataURL();
      window.postMessage(JSON.stringify({action: 0, data: data}));
    }
  </script>
</body>
</html>
` ;

var _width , _height ;
export default class WebCanvas extends Component {
  webview = {};
  constructor ( props ) {
    super ( props );
    this . state = {
      height: this . props . height ,
      width: this . props . width
    }
  }
  // 铅笔
  _pen (){
    this . post ({ action: 1 })
  }
  // 橡皮
  _clean (){
    this . post ({ action: 2 })
  }
  // 初始化画板
  _init (){
    this . post ({ action: '-1' })
  }

  // 以url的形式添加背景
  _addImageUrl ( data ){
    this . post ({ action: 4 , data: data })
  }

  // 以base64的形式添加背景
  _addImageBase64 ( data ){
    this . post ({ action: 5 , data: data })
  }

  _addImage ( data ){
    this . post ({ action: 4 , data: data })
  }

  // 得到图片的base64形式
  _getBase64 (){
    this . post ({ action: 0 })
  }

  // 图片右转
  _rotateRight (){
    this . post ({ action: 3 })
  }

  post ( obj ){
    this . webview . postMessage ( JSON . stringify ( obj ));
  }

  webviewload (){
    // alert('加载成功!')
    this . webview . injectJavaScript ( 'init_canvas(' + this . props . width + ', ' + this . props . height + ');' );

    if ( this . props . onLoad ){
      this . props . onLoad ();
    }
  }

  messageHandler ( e ){
    var obj = JSON . parse ( e . nativeEvent . data );
    if ( obj . action == 0 ){
      this . props . handleBase64 ( obj . data );
    }
  }

  render () {
    return (
      < View style = { [ styles . container , { width: this . state . width , height: this . state . height }] } >  
        < WebView
          style = { { width: this . state . width , height: this . state . height , backgroundColor: "rgba(0,0,0,0)" } }
          ref = { ( w ) => { this . webview = w } }
          onLoad = {this . webviewload . bind ( this ) }
          source = { { html: html } }
          onMessage = {this . messageHandler . bind ( this ) }
          javaScriptEnabled = {true}
          domStorageEnabled = {false}
          automaticallyAdjustContentInsets = {true}
          scalesPageToFit = {false}
          />
          { /* <TouchableOpacity style={{ height:100 }} onPress={()=>this.webview.reload()}>
            <Text style={{ color:"red" }}>刷新</Text>
          </TouchableOpacity> */ }
      </ View >
    );
  }
}

const styles = StyleSheet . create ({
    container:
        backgroundColor: 'rgba(0,0,0,0)' ,
    }
}); 

 类似资料: