写点什么

如何把 Ai 绘画工具放到我们的 App 中

作者:Onegun
  • 2023-04-13
    四川
  • 本文字数:3790 字

    阅读完需:约 12 分钟

如何把Ai绘画工具放到我们的App中

Scribble Diffusion 是一个简单的在线服务,它使用 AI 将粗略的草图转换为精致的图像,每一张图像都是不同的(而且没有版权困扰)。简单来说,我们只需要「用画笔描绘一张草图,在输入描述后稍等片刻」,随后就会为你生成一幅画。这幅画可以多次生成,每次生成的结果也都大不相同。


Scribble Diffusion 的能力大概是这样的(左边是我画的,右边是 TA 画的)

a photo of grassland with cloud(有云朵的草地)


the sun setting behind the mountains(山后落日)


A lovely kitten(小猫咪呀)


我发现 Scribble Diffusion 作画的能力非常出乎意料,而且可以根据你的描述来定义不同的照片风格(比如照片,油画,素描等等),于是就产生了搬运到 FinClip 中作为小程序的想法了(毕竟开箱即用,也不需要做什么配置)。


调研官网之后发现官网中的元素非常简单,正因如此,我觉得把「Scribble Diffusion」搬运到 FinClip 小程序里大概要分这样几步:


  1. 使用 canvas 实现画板,能够在小程序中进行绘画;

  2. 提供输入框与生成按钮,能够补充图片的描述和生成的按钮;

  3. 获取生成的图片链接进行展示。

使用小程序实现画板

我们可以使用小程序来实现一个画板,使用 canvas 标签实现画笔功能。用户可以在画板上绘制画作,也可以选择清空画板操作。


下面是一个示例代码:


<!--画布区域--><view class="canvas_area">    <canvas id="myCanvas" canvas-id="myCanvas" class="myCanvas"        disable-scroll="false"        bindtouchstart="touchStart"        bindtouchmove="touchMove"        bindtouchend="touchEnd">    </canvas></view><view class="clearBtn" bindtap="reset">  清空画板</view>
复制代码


Page({  data: {    isProcessing: false,    prompt: '',    scribble: null,    pen : 2, //画笔粗细默认值    color : '#000000', // 画笔颜色默认值    result: null,    text: ''  },  startX: 0, //保存X坐标轴变量  startY: 0, //保存X坐标轴变量
onLoad(params) { wx.createSelectorQuery().select('#myCanvas').context((res) => { this.context = res.context }).exec() },
//手指触摸动作开始 touchStart: function (e) { //得到触摸点的坐标 this.startX = e.changedTouches[0].x this.startY = e.changedTouches[0].y // this.context = wx.createContext()
this.context.setStrokeStyle(this.data.color) this.context.setLineWidth(this.data.pen) this.context.setLineCap('round') // 让线条圆润 this.context.beginPath() }, //手指触摸后移动 touchMove: function (e) { var startX1 = e.changedTouches[0].x var startY1 = e.changedTouches[0].y
this.context.moveTo(this.startX, this.startY) this.context.lineTo(startX1, startY1) this.context.stroke()
this.startX = startX1; this.startY = startY1; //只是一个记录方法调用的容器,用于生成记录绘制行为的actions数组。context跟<canvas/>不存在对应关系,一个context生成画布的绘制动作数组可以应用于多个<canvas/> wx.drawCanvas({ canvasId: 'myCanvas', reserve: true, actions: this.context.getActions() // 获取绘图动作数组 }) }, //手指触摸动作结束 touchEnd: function () { var imageData = wx.canvasGetImageData({ canvasId: 'myCanvas', height: 250, width: 250, x: 0, y: 0, success(res){ return res.data } }) }, //清除画板 reset: function(){ this.context.clearRect(0, 0, 400, 400); this.context.draw(true) }})
复制代码

提供输入框和生成按钮

我们需要提供一个 input 输入框,供用户输入 prompt;同时,我们需要提供一个按钮,点击时会触发响应事件,将 canvas 内容生成图片,同时将 prompt 输入作为参数,提交给服务端进行图片生成。


这里是示例代码:

<!-- 输入框 --><view class="imageDes">   <view class="formInput">     <input class="input" type="text" name="go"  placeholder="用关键词描述画的内容" bindinput="update"/>  </view></view>
复制代码


Page({  ... 省略上述代码  // 更新表单提交按钮状态  update(e){    this.setData({      prompt : e.detail.value    })  },})
复制代码

获取生成的图片链接并展示

当用户点击生成图片按钮后,我们会将 canvas 内容和用户输入的 prompt 作为参数提交给服务端进行图片生成。服务端会返回生成的图片链接,我们需要将它展示给用户。


在下面的示例代码中,我们服务端发送 POST 请求,然后解析返回的 JSON 数据,获取图片链接,并将其添加到页面中。用户就可以看到生成的图片了。

<!-- 绘图结果 --><view class="result" wx:if="{{result}}">  <view class="resultBox">    <view class="content">      <image class="content" src="{{result}}" mode="aspectFit" />     </view>    <view class="download">      <view class="btn" bindtap="download">        下载      </view>    </view>  </view></view>
复制代码


Page({  ... 省略上述代码  async getCanvasImage() {    return new Promise((resolve, reject) => {      wx.canvasToTempFilePath({        x: 0,        y: 0,        width: 250,        height: 250,        destWidth: 250,        destHeight: 250,        canvasId: 'myCanvas',        success(res) {          console.log(res.tempFilePath)          resolve(res.tempFilePath)        },        fail(err) {          console.log(err)        }      })    })  },  async upload(image) {    return new Promise((resolve) => {      wx.uploadFile({        url: 'xxxxxx',        filePath: image,        name: 'file',        success (res){          const data = JSON.parse(res.data)          resolve(data.url)        },        fail(err){          console.log('上传失败')          console.log(err)        }      })    })  },	async sleep(time) {    return new Promise((resolve) => {      setTimeout(() => {        resolve()      }, time)    })  },  async handleSubmit(e) {    if (!this.data.prompt) {      return    }    wx.showLoading({      title: '生成中',    })    try {      const prompt = this.data.prompt      const image = await this.getCanvasImage()      this.setData({        error: null,        isProcessing: true      });      const url = await this.upload(image)      console.log('图片', url)      const body = {        prompt: prompt,        image: url,      };      const response = await my_fetch.fetch( {        url: "https://scribblediffusion.com/api/predictions",        method: "POST",        headers: {          "Content-Type": "application/json",        },        params: JSON.stringify(body),      });      let prediction = response.data;      console.log('预测', prediction)
if (response.statusCode !== 201) { wx.showToast({ title: '生成失败', duration: 2000 }) this.setData({ error: '生成失败' }); return; } while ( prediction.status !== "succeeded" && prediction.status !== "failed" ) { console.log(prediction.status) await this.sleep(500); const response = await my_fetch.fetch({ url:"https://scribblediffusion.com/api/predictions/" + prediction.id, }); prediction = response.data; if (response.statusCode !== 200) { this.setData({ error: prediction.detail }); return; } } if (Array.isArray(prediction.output) && prediction.output.length > 1) { wx.hideLoading() this.setData({ isProcessing: false, result: prediction.output[1] }); } else { wx.hideLoading() wx.showToast({ title: '生成失败', duration: 2000 }) this.setData({ isProcessing: false, error: '生成失败' }) } } catch (error) { wx.hideLoading() console.log(error) wx.showToast({ title: '生成失败', duration: 2000 }) } },})
复制代码


生成完小程序之后,再通过 FinClip 上传小程序就可以在 App 获得画板功能啦!我把这个小程序上传到了「FinClip 小程序应用市场」中,你可以扫描下方的二维码随意体验,总的来说,还是挺好玩的。


发布于: 刚刚阅读数: 3
用户头像

Onegun

关注

这个Coder不太Cold 2021-08-25 加入

前端划水第一名🥇

评论

发布
暂无评论
如何把Ai绘画工具放到我们的App中_AI_Onegun_InfoQ写作社区