Skip to content

Instantly share code, notes, and snippets.

@rickkk856
Last active May 17, 2024 03:38
Show Gist options
  • Save rickkk856/6a2800cc84dd8fd456074e5a467edc47 to your computer and use it in GitHub Desktop.
Save rickkk856/6a2800cc84dd8fd456074e5a467edc47 to your computer and use it in GitHub Desktop.
Drawing Interface For Google Colaboratory - Paint
#@title <font color='red'>Drawing APP</font> {vertical-output: true, run: "auto"}
import ipywidgets as widgets
from ipywidgets import Layout, Button, Box
from IPython.display import display, HTML, Image
from google.colab.output import eval_js
from base64 import b64decode
Square_Size = 256 #@param ["256", "512"] {type:"raw"}
Brush_Size = 30 #@param {type:"slider", min:0, max:100, step:5}
filename = "my_drawing"#@param [] {allow-input: true}
filename = filename + ".png"
js_code = '''
<style>
.colors-buttons div {
width: 30px;
height: 30px;
margin: 2px;}
div {
display: flex;
}
canvas{border:1px solid black !important;}
</style>
<canvas id="myCanvas" width="%d" height="%d"></canvas>
<div class="colors-buttons">
<div class="color" style="background-color: #000000;" id-color="#000000"></div>
<div class="color" style="background-color: #FFFFFF;" id-color="#FFFFFF"></div>
<div class="color" style="background-color: #FFFF00;" id-color="#FFFF00"></div>
<div class="color" style="background-color: #FF00FF;" id-color="#FF00FF"></div>
<div class="color" style="background-color: #00FFFF;" id-color="#00FFFF"></div>
<div class="color" style="background-color: #FF0000;" id-color="#FF0000"></div>
<div class="color" style="background-color: #0000FF;" id-color="#0000FF"></div>
<div class="color" style="background-color: #00FF00;" id-color="#00FF00"></div>
</div>
<script>
var canvas = document.querySelector('canvas')
var ctx = canvas.getContext('2d')
ctx.fillStyle = 'white';
ctx.fillRect( 0, 0, canvas.width, canvas.height)
var Brush_Size = %d
var button = document.querySelector('button')
var mouse = {x: 0, y: 0}
canvas.addEventListener('mousemove', function(e) {
mouse.x = e.pageX - this.offsetLeft
mouse.y = e.pageY - this.offsetTop
})
canvas.onmousedown = ()=>{
ctx.beginPath()
ctx.moveTo(mouse.x, mouse.y)
canvas.addEventListener('mousemove', onPaint)
}
canvas.onmouseup = ()=>{
canvas.removeEventListener('mousemove', onPaint)
}
var onPaint = ()=>{
ctx.fillRect(mouse.x-( Brush_Size/2), mouse.y-(Brush_Size/2), Brush_Size, Brush_Size)
ctx.stroke()
}
const colors = document.getElementsByClassName('color');
Array.from(colors).forEach(color => {
color.addEventListener('click', (event) => {
const colorSelected = event.target.getAttribute('id-color');
ctx.fillStyle = colorSelected;
});
});
// FINISH BUTTON
var data = new Promise(resolve=>{
button.onclick = ()=>{
resolve(canvas.toDataURL('image/jpg'))
}
})
</script>
'''
## Function to Appear Image Canvas
def draw(filename=filename, w=Square_Size, h=Square_Size, Brush_Size=Brush_Size):
display(HTML(js_code % (w, h, Brush_Size)))
data = eval_js("data")
binary = b64decode(data.split(',')[1])
if AttributeError:
pass
with open(filename, 'wb') as f:
f.write(binary)
return len(binary)
if button2.on_click(on_button_clicked2):
pass
## Action for Reset Button
def on_button_clicked(b):
with output:
#display(HTML(canvas_html % ( w=$Square_Size, h=$Square_Size, Brush_Size=$Brush_Size)))
data = eval_js("data")
binary = b64decode(data.split(',')[1])
with open(filename, 'wb') as f:
f.write(binary)
return len(binary)
## Show Save Button & Save outputs
button = widgets.Button(description="Save")
button.on_click(on_button_clicked)
output = widgets.Output()
display(button, output)
## Show Canvas for the First Time
draw(filename=filename, w=Square_Size, h=Square_Size, Brush_Size=Brush_Size)
print("Image Saved at")
@aastavsashasen
Copy link

It works great!

@rickkk856
Copy link
Author

@aastavsashasen This was a fork of another gist code, they are almost the same, but since you liked this one, you should try the other ones because they might be helpful.

@xinwei-zhuang
Copy link

is it possible to clear a canvas? I saw you have some func but not sure how to modify it to clear all content...

@rickkk856
Copy link
Author

rickkk856 commented Dec 9, 2021

@xinwei-zhuang try this fork... it maybe it is better for what you need

Or maybe this modified version, but it's not working so well.

#@title <font color='red'>DRAW APP V2</font> {vertical-output: true, run: "auto"}
import ipywidgets as widgets
from IPython.display import display, HTML, Image
from google.colab.output import eval_js
from base64 import b64decode
from datetime import datetime
from termcolor import colored

Square_Size = 256 #@param ["256", "512"] {type:"raw"}
Brush_Size = 30 #@param {type:"slider", min:0, max:100, step:5}
filename = "your_name_here.jpg"

print(colored("Draw the boundary","red"))

canvas_html = """
  <style>
    .colors-buttons div {
        width: 30px;
        height: 30px;
        margin: 1px;
        border: 1px solid black !important;}
    div {
        display: inline-block;
    }
    canvas{border:1px solid black !important;}
  </style>

  <canvas id="myCanvas" width="%d" height="%d"></canvas>

  <div class="colors-buttons">
    <div class="color" style="background-color: #000000;" id-color="#000000"></div>
    <div class="color" style="background-color: #FFFFFF;" id-color="#FFFFFF"></div>
    <div class="color" style="background-color: #FFFF00;" id-color="#FFFF00"></div>
    <div class="color" style="background-color: #FF00FF;" id-color="#FF00FF"></div>
    <div class="color" style="background-color: #00FFFF;" id-color="#00FFFF"></div>
    <div class="color" style="background-color: #FF0000;" id-color="#FF0000"></div>
    <div class="color" style="background-color: #0000FF;" id-color="#0000FF"></div>
    <div class="color" style="background-color: #00FF00;" id-color="#00FF00"></div>
  </div>

  <div>
    <button id="save">Save</button>
    <button id="reset">Reset</button>
    <button id="exit">Exit</button>
  </div>
  


  <script>
  var canvas = document.querySelector('canvas')
  var ctx = canvas.getContext('2d')

  ctx.fillStyle = 'white';
  ctx.fillRect( 0, 0, canvas.width, canvas.height)
  var Brush_Size = %d


  var button = document.querySelector('button')
  var mouse = {x: 0, y: 0}
  
  var clear_button = document.querySelector('#reset')
  var button = document.querySelector('#save')
  var exit_button = document.querySelector('#exit')
  
  canvas.addEventListener('mousemove', function(e) {
    mouse.x = e.pageX - this.offsetLeft
    mouse.y = e.pageY - this.offsetTop
  })
  canvas.onmousedown = ()=>{
    ctx.beginPath()
    ctx.moveTo(mouse.x, mouse.y)
    
    canvas.addEventListener('mousemove', onPaint)
  }
  canvas.onmouseup = ()=>{
    canvas.removeEventListener('mousemove', onPaint)
  }
  var onPaint = ()=>{

    ctx.fillRect(mouse.x-( Brush_Size/2), mouse.y-(Brush_Size/2), Brush_Size, Brush_Size)
    ctx.stroke()
  }

  const colors = document.getElementsByClassName('color');

  Array.from(colors).forEach(color => {
      color.addEventListener('click', (event) => {
          const colorSelected = event.target.getAttribute('id-color');
          ctx.fillStyle = colorSelected;
      });
  });

    
    clear_button.onclick = ()=>{{
        console.log('Clearing Screen')
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.fillRect(0, 0, canvas.width, canvas.height);
      }}
      canvas.addEventListener('load', function() {{
      console.log('All assets are loaded')
    }})
    var data = new Promise(resolve=>{{
      button.onclick = ()=>{{
        resolve(canvas.toDataURL('image/png'))
      }}
      exit_button.onclick = ()=>{{
      resolve()
    }}
      
    }})
        

  </script>
  """


## Function to Appear Image Canvas
def draw(filename=filename,  w=Square_Size, h=Square_Size, Brush_Size=Brush_Size):
  display(HTML(canvas_html % (w, h, Brush_Size)))
  data = eval_js("data")
  binary = b64decode(data.split(',')[1])
  if AttributeError:
    pass
  with open(filename, 'wb') as f:
    f.write(binary)
  return len(binary)

  
## Action for Save Button
def on_button_clicked2(c):
  #draw(filename=filename,  w=Square_Size, h=Square_Size, Brush_Size=Brush_Size)
  with output:
    now = datetime.now()
    current_time = now.strftime("%H:%M:%S")
    print("Image Saved Again at:", current_time)
  
## Show Save Button & Save outputs
button = widgets.Button(description="Save Image")
button.on_click(on_button_clicked)
output = widgets.Output()
display(button, output)

## Show Canvas for the First Time
draw(filename=filename,  w=Square_Size, h=Square_Size, Brush_Size=Brush_Size)

The problem is that most of the code is in javascript, and collab works in python... so if want to input more parameters like brush size, colors, clear canvas, reset... you need to write them down in JS but to save the image you need to end up with PY. Its a bit hacky but it works.

image

@xinwei-zhuang
Copy link

Many thanks! I find these two post super useful and easy developable.

@CVL1971
Copy link

CVL1971 commented Oct 7, 2022

the script works great, but i have a problem, can you tell me why the save image button stops working when you load the canvas with an image?

var ctx = canvas.getContext('2d')
let newImage = newImage();
newImage.onload = () => {
ctx.drawImage(newImage, 0, 0, 256, 256);
}
newImage.src = 'https://iili.io/QBYTE7.png';

@kremenevskiy
Copy link

the script works great, but i have a problem, can you tell me why the save image button stops working when you load the canvas with an image?

var ctx = canvas.getContext('2d') let newImage = newImage(); newImage.onload = () => { ctx.drawImage(newImage, 0, 0, 256, 256); } newImage.src = 'https://iili.io/QBYTE7.png';

hello, did you solve that problem. out maybe found other way to draw on other images with colab

@eugenechow5
Copy link

Hello, may I please ask how to load an image to the canvas first and then draw on it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment