diff --git a/README.md b/README.md index c717dff..2976406 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,18 @@ Ronin helpers are keywords that facilitates adding coordinates from the canvas i - `(import path shape ~alpha)` Imports a graphic file with format. - `(export path ~format ~quality)` Exports a graphic file with format. - `(open path ~ratio)` Imports a graphic file and resizes the frame. +- `(frame)` Returns a rect of the frame. +- `(resize ~w)` Resizes the canvas to target w and h, returns the rect. +- `(rescale ~w ~h)` Rescales the canvas to target ratio of w and h, returns the rect. +- `(crop ~rect)` Crop canvas to rect. +- `(copy ~rect)` Copy a section of the canvas. +- `(paste copy ~rect)` Paste a section of the canvas. +- `(drag ~rect)` Drag a part of the canvas. +- `(view a b)` View a part of the canvas. +- `(pick ~shape)` Returns the color of a pixel at pos, or of the average of the pixels in rect. - `(move x y)` - `(rotate angle)` -- `(scale x y)` +- `(scale w h)` - `(transform a b c d e f)` - `(setTransform a b c d e f)` - `(resetTransform)` @@ -59,24 +68,11 @@ Ronin helpers are keywords that facilitates adding coordinates from the canvas i - `(text x y p t ~a ~f)` Returns a text shape. - `(svg x y d)` Returns a svg shape. - `(color r g b ~a)` Returns a color object. -- `(offset a b)` Offsets pos a with pos b, returns a. -- `(distance a b)` Get distance between positions. - `(stroke shape color ~thickness)` Strokes a shape. - `(fill ~rect)` Fills a shape. - `(gradient line ~colors 'black'])` Defines a gradient color. - `(guide shape color)` Draws a shape on the guide layer. - `(clear ~rect)` Clears a rect. -- `(frame)` Returns a rect of the frame. -- `(center)` Returns a position of the center of the frame. -- `(resize ~w)` Resizes the canvas to target w and h, returns the rect. -- `(rescale w h)` Rescales the canvas to target ratio of w and h, returns the rect. -- `(crop ~rect)` Crop canvas to rect. -- `(copy ~rect)` Copy a section of the canvas. -- `(paste copy ~rect)` Paste a section of the canvas. -- `(clone a b)` -- `(drag ~rect)` Drag a part of the canvas. -- `(view a b)` View a part of the canvas. -- `(pick ~shape)` Returns the color of a pixel at pos, or of the average of the pixels in rect. - `(theme variable ~el)` - `(pixels fn ~q ~rect)` - `(saturation pixel q)` Change the saturation of pixels. @@ -139,6 +135,8 @@ Ronin helpers are keywords that facilitates adding coordinates from the canvas i - `(dirname ~path)` Returns the name of a folder. - `(filename ~path)` Returns the name of a file. - `(exit ~force)` Exits Ronin. +- `(offset a b)` Offsets pos a with pos b, returns a. +- `(distance a b)` Get distance between positions. - `(echo ...args)` Print arguments to interface. - `(debug arg)` Print arguments to console. - `(time ~rate)` Returns timestamp in milliseconds. diff --git a/desktop/sources/scripts/commander.js b/desktop/sources/scripts/commander.js index 97d62b8..792f5dd 100644 --- a/desktop/sources/scripts/commander.js +++ b/desktop/sources/scripts/commander.js @@ -182,7 +182,7 @@ function Commander (ronin) { if (word === 'pos') { return `(pos ${shape.x} ${shape.y})` } if (word === 'line') { return `(line ${shape.a.x} ${shape.a.y} ${shape.b.x} ${shape.b.y})` } if (word === 'circle') { return `(circle ${shape.cx} ${shape.cy} ${shape.r})` } - if (word === 'x' || word === 'y' || word === 'xy') { return `${shape}` } + if (word === 'x' || word === 'y' || word === 'xy' || word === 'wh') { return `${shape}` } return '' } diff --git a/desktop/sources/scripts/library.js b/desktop/sources/scripts/library.js index d8771ba..393f244 100644 --- a/desktop/sources/scripts/library.js +++ b/desktop/sources/scripts/library.js @@ -21,6 +21,75 @@ function Library (ronin) { return ronin.surface.open(path, ratio) } + // Frame + + this.frame = () => { // Returns a rect of the frame. + return ronin.surface.getFrame() + } + + this.resize = async (w = ronin.surface.bounds().w, h = ronin.surface.bounds().h, fit = true) => { // Resizes the canvas to target w and h, returns the rect. + if (w === this.frame().w && h === this.frame().h) { return } + const rect = { x: 0, y: 0, w, h } + const a = document.createElement('img') + const b = document.createElement('img') + a.src = ronin.surface.el.toDataURL() + await ronin.surface.resizeImage(a, b) + ronin.surface.resize(rect, fit) + return ronin.surface.draw(b, rect) + } + + this.rescale = async (w = 1, h = 1) => { // Rescales the canvas to target ratio of w and h, returns the rect. + const rect = { x: 0, y: 0, w: this.frame().w * w, h: this.frame().h * h } + const a = document.createElement('img') + const b = document.createElement('img') + a.src = ronin.surface.el.toDataURL() + await ronin.surface.resizeImage(a, b) + ronin.surface.resize(rect, true) + return ronin.surface.draw(b, rect) + } + + this.crop = async (rect = this.frame()) => { // Crop canvas to rect. + return ronin.surface.crop(rect) + } + + this.copy = async (rect = this.frame()) => { // Copy a section of the canvas. + return ronin.surface.copy(rect) + } + + this.paste = async (copy, rect = this.frame()) => { // Paste a section of the canvas. + return ronin.surface.paste(copy, rect) + } + + this.drag = (rect = this.frame(), line = this.line()) => { // Drag a part of the canvas. + const pos = { x: line.b.x - line.a.x, y: line.b.y - line.a.y } + const crop = ronin.surface.copy(rect) + ronin.surface.clear(rect) + this.guide({ a: { x: rect.x, y: rect.y }, b: { x: pos.x + rect.x, y: pos.y + rect.y } }) + this.guide(rect) + this.guide(this.offset(rect, { x: pos.x, y: pos.y })) + ronin.surface.context.drawImage(crop, rect.x, rect.y) + } + + this.view = (a, b) => { // View a part of the canvas. + this.guide({ a: { x: a.x, y: a.y }, b: { x: b.x, y: b.y } }) + this.guide(a) + this.guide(b) + ronin.surface.context.drawImage(this.copy(a), b.x, b.y, b.w, b.h) + } + + this.pick = (shape = this.frame()) => { // Returns the color of a pixel at pos, or of the average of the pixels in rect. + const rect = shape.w && shape.h ? shape : this.rect(shape.x, shape.y, 1, 1) + const img = ronin.surface.context.getImageData(rect.x, rect.y, rect.w, rect.h) + const sum = [0, 0, 0] + const count = img.data.length / 4 + for (let i = 0, loop = img.data.length; i < loop; i += 4) { + sum[0] += img.data[i] + sum[1] += img.data[i + 1] + sum[2] += img.data[i + 2] + } + return this.color(this.floor(sum[0] / count), this.floor(sum[1] / count), this.floor(sum[2] / count)) + } + // Transforms this.move = (x, y) => { @@ -31,8 +100,8 @@ function Library (ronin) { ronin.surface.context.rotate(angle) } - this.scale = (x, y) => { - ronin.surface.context.scale(x, y === undefined ? x : y) + this.scale = (w, h) => { + ronin.surface.context.scale(w, h === undefined ? w : h) } this.transform = (a, b, c, d, e, f) => { @@ -96,17 +165,7 @@ function Library (ronin) { this.color = (r, g, b, a = 1) => { // Returns a color object. const hex = '#' + ('0' + parseInt(r, 10).toString(16)).slice(-2) + ('0' + parseInt(g, 10).toString(16)).slice(-2) + ('0' + parseInt(b, 10).toString(16)).slice(-2) - return { r, g, b, a, hex, toString: () => { return `rgba(${r},${g},${b},${a})` }, 0: r, 1: g, 2: b, 3: a, f: [r / 255, g / 255, b / 255] } - } - - this.offset = (a, b) => { // Offsets pos a with pos b, returns a. - a.x += b.x - a.y += b.y - return a - } - - this.distance = (a, b) => { // Get distance between positions. - return Math.sqrt(((ax - bx) * (ax - bx)) + ((ay - by) * (ay - by))) + return { r, g, b, a, hex, toString: () => { return `rgba(${r},${g},${b},${a})` }, 0: r, 1: g, 2: b, 3: a, f: [r / 255, g / 255, b / 255, a] } } // Actions @@ -122,7 +181,11 @@ function Library (ronin) { } this.gradient = (line, colors = ['white', 'black']) => { // Defines a gradient color. - return ronin.surface.linearGradient(line.a.x, line.a.y, line.b.x, line.b.y, colors) + const gradient = ronin.surface.context.createLinearGradient(line.a.x, line.a.y, line.b.x, line.b.y) + colors.forEach((color, i) => { + gradient.addColorStop(i * (1 / (colors.length - 1)), color) + }) + return gradient } this.guide = (shape, color) => { // Draws a shape on the guide layer. @@ -136,85 +199,6 @@ function Library (ronin) { return rect } - // Frame - - this.frame = () => { // Returns a rect of the frame. - return ronin.surface.getFrame() - } - - this.center = () => { // Returns a position of the center of the frame. - const rect = this.frame() - return this.pos(rect.w / 2, rect.h / 2) - } - - this.resize = async (w = ronin.surface.bounds().w, h = ronin.surface.bounds().h, fit = true) => { // Resizes the canvas to target w and h, returns the rect. - if (w === this.frame().w && h === this.frame().h) { return } - const rect = { x: 0, y: 0, w, h } - const a = document.createElement('img') - const b = document.createElement('img') - a.src = ronin.surface.el.toDataURL() - await ronin.surface.resizeImage(a, b) - ronin.surface.resize(rect, fit) - return ronin.surface.draw(b, rect) - } - - this.rescale = async (w, h) => { // Rescales the canvas to target ratio of w and h, returns the rect. - const rect = { x: 0, y: 0, w: this.frame().w * w, h: this.frame().h * h } - const a = document.createElement('img') - const b = document.createElement('img') - a.src = ronin.surface.el.toDataURL() - await ronin.surface.resizeImage(a, b) - ronin.surface.resize(rect, true) - return ronin.surface.draw(b, rect) - } - - this.crop = async (rect = this.frame()) => { // Crop canvas to rect. - return ronin.surface.crop(rect) - } - - this.copy = async (rect = this.frame()) => { // Copy a section of the canvas. - return ronin.surface.copy(rect) - } - - this.paste = async (copy, rect = this.frame()) => { // Paste a section of the canvas. - return ronin.surface.paste(copy, rect) - } - - this.clone = (a, b) => { - ronin.surface.clone(a, b) - return [a, b] - } - - this.drag = (rect = this.frame(), line = this.line()) => { // Drag a part of the canvas. - const pos = { x: line.b.x - line.a.x, y: line.b.y - line.a.y } - const crop = ronin.surface.copy(rect) - ronin.surface.clear(rect) - this.guide({ a: { x: rect.x, y: rect.y }, b: { x: pos.x + rect.x, y: pos.y + rect.y } }) - this.guide(rect) - this.guide(this.offset(rect, { x: pos.x, y: pos.y })) - ronin.surface.context.drawImage(crop, rect.x, rect.y) - } - - this.view = (a, b) => { // View a part of the canvas. - this.guide({ a: { x: a.x, y: a.y }, b: { x: b.x, y: b.y } }) - this.guide(a) - this.guide(b) - ronin.surface.context.drawImage(ronin.surface.copy(a), b.x, b.y, b.w, b.h) - } - - this.pick = (shape = this.frame()) => { // Returns the color of a pixel at pos, or of the average of the pixels in rect. - const rect = shape.w && shape.h ? shape : this.rect(shape.x, shape.y, 1, 1) - const img = ronin.surface.context.getImageData(rect.x, rect.y, rect.w, rect.h) - const sum = [0, 0, 0] - const count = img.data.length / 4 - for (let i = 0, loop = img.data.length; i < loop; i += 4) { - sum[0] += img.data[i] - sum[1] += img.data[i + 1] - sum[2] += img.data[i + 2] - } - return this.color(this.floor(sum[0] / count), this.floor(sum[1] / count), this.floor(sum[2] / count)) - } - this.theme = (variable, el = document.documentElement) => { // ex. (theme "f_main") -> :root { --f_main: "#fff" } return getComputedStyle(el).getPropertyValue(`--${variable}`) @@ -547,6 +531,16 @@ function Library (ronin) { ronin.source.quit(force) } + this.offset = (a, b) => { // Offsets pos a with pos b, returns a. + a.x += b.x + a.y += b.y + return a + } + + this.distance = (a, b) => { // Get distance between positions. + return Math.sqrt(((ax - bx) * (ax - bx)) + ((ay - by) * (ay - by))) + } + this.echo = (...args) => { // Print arguments to interface. ronin.log(args) return args diff --git a/desktop/sources/scripts/ronin.js b/desktop/sources/scripts/ronin.js index 4f5738a..82eb691 100644 --- a/desktop/sources/scripts/ronin.js +++ b/desktop/sources/scripts/ronin.js @@ -152,6 +152,7 @@ function Ronin () { w: this.mouseOrigin.x ? pos.x - this.mouseOrigin.x : 0, h: this.mouseOrigin.y ? pos.y - this.mouseOrigin.y : 0 } + const wh = rect.w + ' ' + rect.h const line = { a: { x: this.mouseOrigin.x, y: this.mouseOrigin.y }, b: { x: pos.x, y: pos.y } @@ -163,7 +164,7 @@ function Ronin () { r: d.toFixed(2), edge: { x: rect.x - rect.w, y: rect.y - rect.h, w: rect.w * 2, h: rect.h * 2 } } - return { x, y, xy, d, line, rect, pos, circle, type, 'is-down': type !== 'mouse-up' ? true : null } + return { x, y, xy, wh, d, line, rect, pos, circle, type, 'is-down': type !== 'mouse-up' ? true : null } } // Zoom diff --git a/desktop/sources/scripts/surface.js b/desktop/sources/scripts/surface.js index 0c57018..ef449c0 100644 --- a/desktop/sources/scripts/surface.js +++ b/desktop/sources/scripts/surface.js @@ -71,15 +71,6 @@ function Surface (ronin) { context.closePath() } - this.linearGradient = function (x1, y1, x2, y2, colors, context = this.context) { - const gradient = context.createLinearGradient(x1, y1, x2, y2) - const step = 1 / (colors.length - 1) - colors.forEach((color, i) => { - gradient.addColorStop(i * step, color) - }) - return gradient - } - // Tracers this.trace = function (shape, context) { @@ -113,13 +104,11 @@ function Surface (ronin) { } this.traceLine = function (line, context) { - console.log(line) context.moveTo(line.a.x, line.a.y) context.lineTo(line.b.x, line.b.y) } this.tracePoly = function (poly, context) { - console.log('poly?') const positions = Object.values(poly) const origin = positions.shift() context.moveTo(origin.x, origin.y) @@ -206,7 +195,6 @@ function Surface (ronin) { } this.drawGuide = function (shape, color = 'white', context = this.guide) { - console.log(shape) if (!shape) { return } this.stroke(shape.rect || shape, 'black', 4, context) if (shape.pos) { this.stroke(shape.pos, 'black', 4, context) } @@ -223,10 +211,6 @@ function Surface (ronin) { } } - this.clone = function (a, b) { - this.context.drawImage(this.el, a.x, a.y, a.w, a.h, b.x, b.y, b.w, b.h) - } - this.resize = function (size, fit = false) { const frame = this.getFrame() if (frame.w === size.w && frame.h === size.h) { return } @@ -280,7 +264,7 @@ function Surface (ronin) { } this.paste = function (copy, rect) { - return this.context.drawImage(copy, 0, 0, rect.w, rect.h, rect.x, rect.y, rect.w, rect.h) + return this.context.drawImage(copy, rect.x, rect.y, rect.w, rect.h) } this.resizeImage = function (src, dst, type = 'image/png', quality = 1.0) {