summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--css/sally.css9
-rw-r--r--image.html2
-rw-r--r--index.html7
-rw-r--r--irssi.txt5
-rw-r--r--js/app.js1
-rw-r--r--js/clipboard.js17
-rw-r--r--js/draw.js7
-rw-r--r--js/lex.js12
-rw-r--r--js/matrix.js2
-rw-r--r--js/photo.js9
-rw-r--r--js/ui/brush.js4
-rw-r--r--js/ui/canvas.js2
-rw-r--r--js/ui/controls.js3
-rw-r--r--js/vendor/color.js251
-rw-r--r--js/vendor/text-encoder-lite.js141
-rw-r--r--webcam.html104
16 files changed, 531 insertions, 45 deletions
diff --git a/css/sally.css b/css/sally.css
index 3422979..f360b0c 100644
--- a/css/sally.css
+++ b/css/sally.css
@@ -22,10 +22,10 @@ body {
}
a {display: block}
-a:link, a:visited {text-decoration: none; color: #3b3740}
+a:link, a:visited {text-decoration: none; color: #6b6760}
+a:hover { text-decoration: underline }
-{overflow: auto;}
-.faded { color: 404040; }
+.faded { color: #404040; }
.rapper, .block {
float: left;
height:auto;
@@ -74,7 +74,7 @@ a:link, a:visited {text-decoration: none; color: #3b3740}
background-size: 4px 4px;
}
}
-span { min-width: 8px; line-height: 15px; display: inline-block; }
+span,a { min-width: 8px; line-height: 15px; display: inline-block; }
.rapper { cursor: crosshair; }
body.grid span { border-right: 1px solid #444; border-bottom: 1px solid #444; }
body.grid div { border-left: 1px solid #444; }
@@ -192,7 +192,6 @@ textarea { font-size:12pt; width: 37vw; height: 300px; background: #333; color:
border: 1px solid #0f0;
color: #0f0;
width: 100%;
- display: none;
}
#upload_button.uploading {
background: transparent;
diff --git a/image.html b/image.html
index 7132c2c..00b98db 100644
--- a/image.html
+++ b/image.html
@@ -35,7 +35,7 @@ label { min-width: 70px; display: inline-block; }
<script src="js/vendor/jquery-2.1.4.min.js"></script>
<script src="js/photo.js"></script>
<script src="js/util.js"></script>
-<script src="/dither/js/color.js"></script>
+<script src="js/vendor/color.js"></script>
<script>
var basehref_partz = window.location.href.split("/")
basehref_partz.pop()
diff --git a/index.html b/index.html
index 999ded4..d00dc06 100644
--- a/index.html
+++ b/index.html
@@ -1,3 +1,4 @@
+<!-- http://jollo.org/licensing/public/LNT-1.txt -->
<meta charset="UTF-8">
<link rel="stylesheet" href="css/sally.css" type="text/css" charset="utf-8" />
<link rel="stylesheet" href="css/ak.css" type="text/css" charset="utf-8" />
@@ -50,7 +51,9 @@
<span id="webcam_el" class="tool">webcam</span>
<span id="load_el" class="tool">load</span>
<span id="save_el" class="tool">save</span>
- <span id="clear_el" class="tool">clear</span><br>
+ <span id="clear_el" class="tool">new</span>
+ <a href="http://asdf.us/im/gallery/?tag=ascii" target="_blank">gallery</a>
+ <br>
</div>
<div id="import_rapper">
@@ -93,6 +96,7 @@
// lex.opacity = 1
</script>
<script src="js/vendor/colorcode.js"></script>
+<script src="js/vendor/text-encoder-lite.js"></script>
<script src="js/vendor/dataUriToBlob.js"></script>
<script src="js/vendor/FileSaver.js"></script>
@@ -122,3 +126,4 @@
<script src="js/ui/selection.js"></script>
<script src="js/app.js"></script>
+
diff --git a/irssi.txt b/irssi.txt
index 9a3011c..42ada16 100644
--- a/irssi.txt
+++ b/irssi.txt
@@ -88,9 +88,10 @@ If you do not want to do the autojoin thing these are the commands you'd normall
SETTING UP IRSSI TO AUTOJOIN #SALLY
===================================
-First run irssi, then paste in these commands (changing yournick to your preferred nickname, etc)
+First run irssi, then paste in these commands.
+Please change YOUR_NICK_HERE to your preferred username!
-/network add -nick yournick -user yournick -realname "your name" Jollo
+/network add -nick YOUR_NICK_HERE -user YOUR_NICK_HERE -realname "YOUR NAME HERE" Jollo
/server add -network Jollo -auto -ssl irc.jollo.org 9999
/channel add -auto #sally Jollo
/save
diff --git a/js/app.js b/js/app.js
index a96cc35..3531d7c 100644
--- a/js/app.js
+++ b/js/app.js
@@ -9,6 +9,7 @@ var focused
var canvas, tools, palette, controls, brush, mode
var current_tool, current_filetool, current_canvas
+var mouse = { x: 0, y: 0 }
function init () {
build()
diff --git a/js/clipboard.js b/js/clipboard.js
index 7e683dc..9c3b1b2 100644
--- a/js/clipboard.js
+++ b/js/clipboard.js
@@ -122,7 +122,8 @@ var clipboard = (function () {
lex.build()
}
}
-
+
+ current_filetool && current_filetool.blur()
},
import_text: function () {
@@ -240,6 +241,7 @@ var clipboard = (function () {
}
+ // http...?a=1&b=2&b=3 -> {a: '1', b: ['2', '3']}
function parse_url_search_params(url){
var params = {}
url = url.split('?')
@@ -270,7 +272,7 @@ var clipboard = (function () {
function fetch_url(url, f, type){
type = type || 'arraybuffer'
url = "/cgi-bin/proxy?" + url
- // url = "http://198.199.72.134/cors/" + url
+ //url = "http://198.199.72.134/cors/" + url
var xhr = new XMLHttpRequest()
xhr.open('GET', url, true)
xhr.responseType = type
@@ -293,11 +295,20 @@ var clipboard = (function () {
clipboard.import_colorcode(itxt.data, true)
}
}
-
+
+ function sally_url_convert(url){
+ var png_regex = /^https?:\/\/jollo\.org\/den\/sallies\/([0-9]+)\/([^.]+)\.png$/
+ var matches = url.match(png_regex)
+ if (!matches) return url
+ return 'http://jollo.org/den/sallies/' + matches[1] + '/raw-' + matches[2] + '?.txt'
+ // txt suffix to force asdf proxy
+ }
+
exports.load_from_location = function(){
var params = parse_url_search_params(window.location + '')
if (!params.url) return
var url = params.url
+ url = sally_url_convert(url)
var type = get_filetype(url)
switch (type){
case 'txt':
diff --git a/js/draw.js b/js/draw.js
index 77e149b..cedfea2 100644
--- a/js/draw.js
+++ b/js/draw.js
@@ -43,18 +43,19 @@ var draw = (function(){
}
function stamp (canvas, brush, x, y, erasing) {
- hh = brush.w/2|0
+ var hh = brush.w/2|0
brush.forEach(function(lex, s, t){
s = round( s + x-hh )
t = round( t + y-hh )
- if (lex.opacity > 0 && s >= 0 && s < canvas.w && t >= 0 && t < canvas.h) {
+ if (s >= 0 && s < canvas.w && t >= 0 && t < canvas.h) {
+ if (lex.opacity === 0 && lex.char === ' ') return;
var aa = canvas.aa[t][s]
undo.save_lex(s, t, aa)
if (erasing) {
aa.erase(lex)
}
else {
- aa.paint(lex)
+ aa.stamp(lex, brush)
}
}
})
diff --git a/js/lex.js b/js/lex.js
index e684eea..308f666 100644
--- a/js/lex.js
+++ b/js/lex.js
@@ -65,10 +65,9 @@ Lex.prototype.assign = function (lex){
this.opacity = lex.opacity
this.build()
}
-Lex.prototype.paint = function (lex){
- if (lex.opacity == 0) return
+Lex.prototype.stamp = function (lex, brush){
if (brush.draw_fg) this.fg = lex.fg
- if (brush.draw_bg) this.bg = lex.bg
+ if (brush.draw_bg && lex.opacity > 0) this.bg = lex.bg
if (brush.draw_char) this.char = lex.char
this.opacity = 1
this.build()
@@ -85,13 +84,6 @@ Lex.prototype.erase = function (){
this.opacity = 1
this.build()
}
-Lex.prototype.fill = function(lex){
- this.fg = lex.fg
- this.bg = lex.bg
- this.char = lex.char
- this.opacity = lex.opacity
- this.build()
-}
Lex.prototype.eq = function(lex){
return lex && this.fg == lex.fg && this.bg == lex.bg && this.char == lex.char
}
diff --git a/js/matrix.js b/js/matrix.js
index 4c8976c..275e6b6 100644
--- a/js/matrix.js
+++ b/js/matrix.js
@@ -112,7 +112,7 @@ Matrix.prototype.fill = function(lex){
this.char = lex.char
this.opacity = lex.opacity
this.forEach(function(el,x,y){
- el.fill(lex)
+ el.assign(lex)
el.build()
})
}
diff --git a/js/photo.js b/js/photo.js
index ae4558e..3f72cfc 100644
--- a/js/photo.js
+++ b/js/photo.js
@@ -108,12 +108,15 @@ var Photo = (function(){
null,
null,
]
- var colors = COLORS, recolor_fn = null
+ var colors = COLORS, recolor_fn = null, shade_fn = null
var canvas = document.createElement("canvas"), ctx = canvas.getContext('2d'), pixels
function set_colors (a) {
colors = a
}
+ function set_shade_fn (fn) {
+ shade_fn = fn
+ }
function set_recolor_fn (fn) {
recolor_fn = fn
}
@@ -154,6 +157,9 @@ var Photo = (function(){
pixel[1] = data[t+1]
pixel[2] = data[t+2]
pixel[3] = data[t+3]
+ if (shade_fn) {
+ shade_fn(data, pixel, j, i, w, h)
+ }
if (Photo.denoise) { denoise_pixel(data, w, h, i, j, pixel, Photo.denoise) }
row[j] = closest_to(pixel)
}
@@ -289,6 +295,7 @@ var Photo = (function(){
reds: REDS,
yellows: YELLOWS,
blues: BLUES,
+ set_shade_fn: set_shade_fn,
set_recolor_fn: set_recolor_fn,
set_colors: set_colors,
closest_to: closest_to,
diff --git a/js/ui/brush.js b/js/ui/brush.js
index 8cc858f..668538f 100644
--- a/js/ui/brush.js
+++ b/js/ui/brush.js
@@ -41,7 +41,7 @@ var brush = (function(){
}
else {
fillColor = brush.bg
- lex.fill(brush)
+ lex.assign(brush)
}
brush.focus(x, y)
})
@@ -55,7 +55,7 @@ var brush = (function(){
lex.clear()
}
else {
- lex.fill(brush)
+ lex.assign(brush)
}
brush.focus(x, y)
})
diff --git a/js/ui/canvas.js b/js/ui/canvas.js
index e241fd1..75b8f97 100644
--- a/js/ui/canvas.js
+++ b/js/ui/canvas.js
@@ -52,6 +52,8 @@ var canvas = current_canvas = (function(){
})
lex.span.addEventListener("mousemove", function(e){
+ mouse.x = x
+ mouse.y = y
if (is_mobile) return
if (! dragging) return
if (drawing) {
diff --git a/js/ui/controls.js b/js/ui/controls.js
index a21e293..c191cc2 100644
--- a/js/ui/controls.js
+++ b/js/ui/controls.js
@@ -72,6 +72,7 @@ var controls = (function(){
undo.new()
undo.save_rect(0, 0, canvas.w, canvas.h)
canvas.erase()
+ current_filetool && current_filetool.blur()
}
controls.webcam = new FileTool (webcam_el)
@@ -119,9 +120,9 @@ var controls = (function(){
})
controls.save = new ClipboardTool (save_el)
controls.save.use = function(){
+ changed && clipboard.upload_png()
clipboard.show()
clipboard.export_mode()
- clipboard.upload_png()
}
controls.load = new ClipboardTool (load_el)
controls.load.use = function(){
diff --git a/js/vendor/color.js b/js/vendor/color.js
new file mode 100644
index 0000000..ac90a3d
--- /dev/null
+++ b/js/vendor/color.js
@@ -0,0 +1,251 @@
+// http://www.easyrgb.com/index.php?X=MATH&H=01#text1
+
+function rgb(x,y,z){
+ r=x; g=y; b=z
+}
+function rgbref(rgb){
+ r=rgb[0]; g=rgb[1]; b=rgb[2];
+}
+function black(){ rgb(0,0,0) }
+function white(){ rgb(255,255,255) }
+function red(){ rgb(255,0,0) }
+function gray(n){ n<1&&(n*=255);rgb(n,n,n) }
+
+function rgb2xyz(rgb){
+ var var_R = ( rgb[0] / 255 ) //R from 0 to 255
+ var var_G = ( rgb[1] / 255 ) //G from 0 to 255
+ var var_B = ( rgb[2] / 255 ) //B from 0 to 255
+
+ if ( var_R > 0.04045 ) var_R = Math.pow( ( var_R + 0.055 ) / 1.055, 2.4)
+ else var_R = var_R / 12.92
+ if ( var_G > 0.04045 ) var_G = Math.pow( ( var_G + 0.055 ) / 1.055, 2.4)
+ else var_G = var_G / 12.92
+ if ( var_B > 0.04045 ) var_B = Math.pow( ( var_B + 0.055 ) / 1.055, 2.4)
+ else var_B = var_B / 12.92
+
+ var_R = var_R * 100
+ var_G = var_G * 100
+ var_B = var_B * 100
+
+ //Observer. = 2°, Illuminant = D65
+ var x = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805
+ var y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722
+ var z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505
+ return [x,y,z];
+}
+function xyz2rgb(xyz){
+ var var_X = xyz[0] / 100 //X from 0 to 95.047 (Observer = 2°, Illuminant = D65)
+ var var_Y = xyz[1] / 100 //Y from 0 to 100.000
+ var var_Z = xyz[2] / 100 //Z from 0 to 108.883
+
+ var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986
+ var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415
+ var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570
+
+ if ( var_R > 0.0031308 ) var_R = 1.055 * Math.pow( var_R, 1 / 2.4 ) - 0.055
+ else var_R = 12.92 * var_R
+ if ( var_G > 0.0031308 ) var_G = 1.055 * Math.pow( var_G, 1 / 2.4 ) - 0.055
+ else var_G = 12.92 * var_G
+ if ( var_B > 0.0031308 ) var_B = 1.055 * Math.pow( var_B, 1 / 2.4 ) - 0.055
+ else var_B = 12.92 * var_B
+
+ var r = clamp(var_R * 255, 0, 255)
+ var g = clamp(var_G * 255, 0, 255)
+ var b = clamp(var_B * 255, 0, 255)
+ return [r,g,b]
+}
+
+function xyz2hunterlab (XYZ) {
+ var X = XYZ[0]
+ var Y = XYZ[1] || 1e-6 // otherwise divide-by-zero error when converting rgb(0,0,0)
+ var Z = XYZ[2]
+ var L = 10 * sqrt( Y )
+ var a = 17.5 * ( ( ( 1.02 * X ) - Y ) / sqrt( Y ) )
+ var b = 7 * ( ( Y - ( 0.847 * Z ) ) / sqrt( Y ) )
+ return [L,a,b]
+}
+
+function hunterlab2xyz (Lab) {
+ var L = Lab[0]
+ var a = Lab[1]
+ var b = Lab[2]
+ var_Y = L / 10
+ var_X = a / 17.5 * L / 10
+ var_Z = b / 7 * L / 10
+
+ Y = Math.pow(var_Y, 2)
+ X = ( var_X + Y ) / 1.02
+ Z = -( var_Z - Y ) / 0.847
+ return [X,Y,Z]
+}
+// Daylight Illuminant (D65)
+var REF_X = 95.047
+var REF_Y = 100.000
+var REF_Z = 108.883
+
+function xyz2cielab (xyz) {
+ var var_X = xyz[0] / ref_X //ref_X = 95.047 Observer= 2°, Illuminant= D65
+ var var_Y = xyz[1] / ref_Y //ref_Y = 100.000
+ var var_Z = xyz[2] / ref_Z //ref_Z = 108.883
+
+ if ( var_X > 0.008856 ) var_X = Math.pow( var_X, 1/3 )
+ else var_X = ( 7.787 * var_X ) + ( 16 / 116 )
+ if ( var_Y > 0.008856 ) var_Y = Math.pow( var_Y, 1/3 )
+ else var_Y = ( 7.787 * var_Y ) + ( 16 / 116 )
+ if ( var_Z > 0.008856 ) var_Z = Math.pow(var_Z, 1/3 )
+ else var_Z = ( 7.787 * var_Z ) + ( 16 / 116 )
+
+ var L = ( 116 * var_Y ) - 16
+ var a = 500 * ( var_X - var_Y )
+ var b = 200 * ( var_Y - var_Z )
+
+ return [L,a,b]
+}
+
+function cielab2xyz (lab){
+ var var_Y = ( lab[0] + 16 ) / 116
+ var var_X = lab[1] / 500 + var_Y
+ var var_Z = var_Y - lab[2] / 200
+
+ if ( Math.pow(var_Y, 3) > 0.008856 ) var_Y = Math.pow(var_Y, 3)
+ else var_Y = ( var_Y - 16 / 116 ) / 7.787
+ if ( Math.pow(var_X, 3) > 0.008856 ) var_X = Math.pow(var_X, 3)
+ else var_X = ( var_X - 16 / 116 ) / 7.787
+ if ( Math.pow(var_Z, 3) > 0.008856 ) var_Z = Math.pow(var_Z, 3)
+ else var_Z = ( var_Z - 16 / 116 ) / 7.787
+
+ var x = REF_X * var_X //ref_X = 95.047 Observer= 2°, Illuminant= D65
+ var y = REF_Y * var_Y //ref_Y = 100.000
+ var z = REF_Z * var_Z //ref_Z = 108.883
+
+ return [x,y,z]
+}
+
+function rgb2hsl (RGB){
+ var R = RGB[0]
+ var G = RGB[1]
+ var B = RGB[2]
+ var var_R = ( R / 255 ) //RGB from 0 to 255
+ var var_G = ( G / 255 )
+ var var_B = ( B / 255 )
+
+ var var_Min = Math.min( var_R, var_G, var_B ) //Min. value of RGB
+ var var_Max = Math.max( var_R, var_G, var_B ) //Max. value of RGB
+ var del_Max = var_Max - var_Min //Delta RGB value
+
+ var H,S;
+ var L = ( var_Max + var_Min ) / 2
+
+ if ( del_Max == 0 ) //This is a gray, no chroma...
+ {
+ H = 0 //HSL results from 0 to 1
+ S = 0
+ }
+ else //Chromatic data...
+ {
+ if ( L < 0.5 ) S = del_Max / ( var_Max + var_Min )
+ else S = del_Max / ( 2 - var_Max - var_Min )
+
+ var del_R = ( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) ) / del_Max
+ var del_G = ( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) ) / del_Max
+ var del_B = ( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) ) / del_Max
+
+ if ( var_R == var_Max ) H = del_B - del_G
+ else if ( var_G == var_Max ) H = ( 1 / 3 ) + del_R - del_B
+ else if ( var_B == var_Max ) H = ( 2 / 3 ) + del_G - del_R
+
+ if ( H < 0 ) H += 1
+ if ( H > 1 ) H -= 1
+ }
+ return [H,S,L]
+}
+function hsl2rgb (H, S, L) {
+ var R,G,B;
+ var var_1, var_2;
+ if ( S == 0 ) { //HSL from 0 to 1
+ R = L * 255 //RGB results from 0 to 255
+ G = L * 255
+ B = L * 255
+ }
+ else {
+ if ( L < 0.5 ) var_2 = L * ( 1 + S )
+ else var_2 = ( L + S ) - ( S * L )
+
+ var_1 = 2 * L - var_2
+
+ R = 255 * hue2rgb( var_1, var_2, H + ( 1 / 3 ) )
+ G = 255 * hue2rgb( var_1, var_2, H )
+ B = 255 * hue2rgb( var_1, var_2, H - ( 1 / 3 ) )
+ }
+ return [R,G,B]
+}
+function hue2rgb( v1, v2, vH ) {
+ if ( vH < 0 ) vH += 1
+ if ( vH > 1 ) vH -= 1
+ if ( ( 6 * vH ) < 1 ) return ( v1 + ( v2 - v1 ) * 6 * vH )
+ if ( ( 2 * vH ) < 1 ) return ( v2 )
+ if ( ( 3 * vH ) < 2 ) return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6 )
+ return ( v1 )
+}
+
+function rgb2cmy (R,G,B){
+ if (R.length) {
+ B = R[2]
+ G = R[1]
+ R = R[0]
+ }
+ var C = 1 - ( R / 255 )
+ var M = 1 - ( G / 255 )
+ var Y = 1 - ( B / 255 )
+ return [C,M,Y]
+}
+function cmy2rgb (C,M,Y){
+ if (C.length) {
+ Y = C[2]
+ M = C[1]
+ C = C[0]
+ }
+ var R = ( 1 - C ) * 255
+ var G = ( 1 - M ) * 255
+ var B = ( 1 - Y ) * 255
+ return [R,G,B]
+}
+function cmy2cmyk (C,M,Y) {
+ if (C.length) {
+ Y = C[2]
+ M = C[1]
+ C = C[0]
+ }
+
+ var var_K = 1
+
+ if ( C < var_K ) var_K = C
+ if ( M < var_K ) var_K = M
+ if ( Y < var_K ) var_K = Y
+ if ( var_K == 1 ) { //Black
+ C = 0
+ M = 0
+ Y = 0
+ }
+ else {
+ C = ( C - var_K ) / ( 1 - var_K )
+ M = ( M - var_K ) / ( 1 - var_K )
+ Y = ( Y - var_K ) / ( 1 - var_K )
+ }
+ var K = var_K
+ return [C,M,Y,K]
+}
+function cmyk2cmy (C,M,Y,K) {
+ if (C.length) {
+ K = C[3]
+ Y = C[2]
+ M = C[1]
+ C = C[0]
+ }
+ var C = ( C * ( 1 - K ) + K )
+ var M = ( M * ( 1 - K ) + K )
+ var Y = ( Y * ( 1 - K ) + K )
+ return [C,M,Y]
+}
+
+
diff --git a/js/vendor/text-encoder-lite.js b/js/vendor/text-encoder-lite.js
new file mode 100644
index 0000000..957fd9b
--- /dev/null
+++ b/js/vendor/text-encoder-lite.js
@@ -0,0 +1,141 @@
+// taken from https://github.com/coolaj86/TextEncoderLite/blob/master/index.js
+// added polyfill at bottom
+
+function TextEncoderLite() {
+}
+function TextDecoderLite() {
+}
+
+(function () {
+'use strict';
+
+// Taken from https://github.com/feross/buffer/blob/master/index.js
+// Thanks Feross et al! :-)
+
+function utf8ToBytes (string, units) {
+ units = units || Infinity
+ var codePoint
+ var length = string.length
+ var leadSurrogate = null
+ var bytes = []
+ var i = 0
+
+ for (; i < length; i++) {
+ codePoint = string.charCodeAt(i)
+
+ // is surrogate component
+ if (codePoint > 0xD7FF && codePoint < 0xE000) {
+ // last char was a lead
+ if (leadSurrogate) {
+ // 2 leads in a row
+ if (codePoint < 0xDC00) {
+ if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
+ leadSurrogate = codePoint
+ continue
+ } else {
+ // valid surrogate pair
+ codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000
+ leadSurrogate = null
+ }
+ } else {
+ // no lead yet
+
+ if (codePoint > 0xDBFF) {
+ // unexpected trail
+ if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
+ continue
+ } else if (i + 1 === length) {
+ // unpaired lead
+ if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
+ continue
+ } else {
+ // valid lead
+ leadSurrogate = codePoint
+ continue
+ }
+ }
+ } else if (leadSurrogate) {
+ // valid bmp char, but last char was a lead
+ if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
+ leadSurrogate = null
+ }
+
+ // encode utf8
+ if (codePoint < 0x80) {
+ if ((units -= 1) < 0) break
+ bytes.push(codePoint)
+ } else if (codePoint < 0x800) {
+ if ((units -= 2) < 0) break
+ bytes.push(
+ codePoint >> 0x6 | 0xC0,
+ codePoint & 0x3F | 0x80
+ )
+ } else if (codePoint < 0x10000) {
+ if ((units -= 3) < 0) break
+ bytes.push(
+ codePoint >> 0xC | 0xE0,
+ codePoint >> 0x6 & 0x3F | 0x80,
+ codePoint & 0x3F | 0x80
+ )
+ } else if (codePoint < 0x200000) {
+ if ((units -= 4) < 0) break
+ bytes.push(
+ codePoint >> 0x12 | 0xF0,
+ codePoint >> 0xC & 0x3F | 0x80,
+ codePoint >> 0x6 & 0x3F | 0x80,
+ codePoint & 0x3F | 0x80
+ )
+ } else {
+ throw new Error('Invalid code point')
+ }
+ }
+
+ return bytes
+}
+
+function utf8Slice (buf, start, end) {
+ var res = ''
+ var tmp = ''
+ end = Math.min(buf.length, end || Infinity)
+ start = start || 0;
+
+ for (var i = start; i < end; i++) {
+ if (buf[i] <= 0x7F) {
+ res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
+ tmp = ''
+ } else {
+ tmp += '%' + buf[i].toString(16)
+ }
+ }
+
+ return res + decodeUtf8Char(tmp)
+}
+
+function decodeUtf8Char (str) {
+ try {
+ return decodeURIComponent(str)
+ } catch (err) {
+ return String.fromCharCode(0xFFFD) // UTF 8 invalid char
+ }
+}
+
+TextEncoderLite.prototype.encode = function (str) {
+ var result;
+
+ if ('undefined' === typeof Uint8Array) {
+ result = utf8ToBytes(str);
+ } else {
+ result = new Uint8Array(utf8ToBytes(str));
+ }
+
+ return result;
+};
+
+TextDecoderLite.prototype.decode = function (bytes) {
+ return utf8Slice(bytes, 0, bytes.length);
+}
+
+}());
+
+if (typeof TextEncoder === 'undefined') TextEncoder = TextEncoderLite
+if (typeof TextDecoder === 'undefined') TextDecoder = TextDecoderLite
diff --git a/webcam.html b/webcam.html
index 7f76131..375a00d 100644
--- a/webcam.html
+++ b/webcam.html
@@ -2,17 +2,19 @@
<link rel="stylesheet" href="css/sally.css" type="text/css" charset="utf-8" />
<style>
#controls { width: 220px; float: left; padding: 10px; }
-label { min-width: 70px; display: inline-block; }
+input { cursor: pointer; }
+label { min-width: 70px; display: inline-block; cursor: pointer; }
#text_style { width: 100px; }
label.cbox { min-width: 50px; }
+canvas { cursor: pointer; }
</style>
<body class="transparent">
<div id="controls">
<label></label>&nbsp;<span id="width_span"></span>x<span id="height_span"></span>
<br>
- <label for="width_el">width</label><input type="range" min="1" max="120" value="40" id="width_el">
+ <label for="width_el">width</label><input type="range" min="1" max="120" value="80" id="width_el">
<br>
- <label for="ratio_el">ratio</label><input type="range" min="0.0" max="8" value="2" step="0.005" id="ratio_el"><br>
+ <label for="ratio_el">ratio</label><input type="range" min="0.0" max="8" value="2.43" step="0.005" id="ratio_el"><br>
<label for="hue_el">hue</label><input type="range" min="-1" max="1" value="0" step="0.005" id="hue_el"><br>
<label for="sat_el">sat</label><input type="range" min="-1" max="1" value="0" step="0.005" id="sat_el"><br>
<label for="lum_el">lum</label><input type="range" min="-1" max="1" value="0" step="0.005" id="lum_el"><br>
@@ -39,16 +41,18 @@ label.cbox { min-width: 50px; }
<div id="image_style"></div>
</body>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
-<script src="http://asdf.us/dither/js/color.js"></script>
-<script src="http://asdf.us/dither/js/util.js"></script>
+<script src="js/vendor/color.js"></script>
+<script src="js/util.js"></script>
<script src="js/photo.js"></script>
<script>
+var canvas = document.createElement("canvas"), ctx = canvas.getContext('2d')
+image_style.appendChild(canvas)
+
var width = parseInt( width_span.innerHTML = width_el.value )
var ratio = parseFloat( ratio_el.value )
-var nn = $(nn_el).prop('checked')
-var invert = $(invert_el).prop('checked')
+var nn = nn_el.checked
+var invert = invert_el.checked
var width_timeout
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
@@ -99,6 +103,69 @@ Photo.set_recolor_fn(function(rgb){
return rgb
})
+var shader_index = 0
+
+var SHADERS = [
+ { name: "none",
+ shader: null
+ },
+ { name: "pixelate",
+ shader: function(d, p, x, y, w, h){
+ rgbpixel(d, p, x - (x%2), y, w, h)
+ }
+ },
+ { name: "flop",
+ shader: function(d, p, x, y, w, h){
+ rgbpixel(d, p, w-x-1, y, w, h)
+ }
+ },
+ { name: "flip",
+ shader: function(d, p, x, y, w, h){
+ rgbpixel(d, p, x, h-y-1, w, h)
+ }
+ },
+ { name: "flip-flop",
+ shader: function(d, p, x, y, w, h){
+ rgbpixel(d, p, w-x-1, h-y-1, w, h)
+ }
+ },
+ { name: "left-mirror",
+ shader: function(d, p, x, y, w, h){
+ rgbpixel(d, p, x < w/2 ? x : w-x-1, y, w, h)
+ }
+ },
+ { name: "right-mirror",
+ shader: function(d, p, x, y, w, h){
+ rgbpixel(d, p, x > w/2 ? x : w-x-1, y, w, h)
+ }
+ },
+ { name: "top-mirror",
+ shader: function(d, p, x, y, w, h){
+ rgbpixel(d, p, x, y > h/2 ? y : h-y-1, w, h)
+ }
+ },
+ { name: "bottom-mirror",
+ shader: function(d, p, x, y, w, h){
+ rgbpixel(d, p, x, y < h/2 ? y : h-y-1, w, h)
+ }
+ },
+ { name: "four-corners",
+ shader: function(d, p, x, y, w, h){
+ rgbpixel(d, p,
+ Math.round(Math.abs(w*(2*(x/w-0.5)))),
+ Math.round(Math.abs(h*(2*((y+0.5)/h-0.5)))),
+ w, h)
+ }
+ },
+]
+
+function rgbpixel(d, p, x, y, w, h) {
+ var t = 4 * (x + y*w)
+ p[0] = d[t]
+ p[1] = d[t+1]
+ p[2] = d[t+2]
+}
+
// Photo.denoise = 2
var hue = 0, sat = 0, lum = 0, quant = 1
@@ -118,13 +185,13 @@ function save (){
}
}
nn_el.addEventListener('change', function(){
- nn = $(nn_el).prop('checked')
+ nn = nn_el.checked
})
invert_el.addEventListener('change', function(){
- invert = $(invert_el).prop('checked')
+ invert = invert_el.checked
})
palette_el.addEventListener('change', function(){
- var palette = $(palette_el).val()
+ var palette = palette_el.value
Photo.set_colors( Photo[palette] )
})
ratio_el.addEventListener("input", function(){
@@ -143,7 +210,17 @@ function listen (el, obj, val) {
obj[val] = parseFloat( el.value )
})
}
-var canvas = document.createElement("canvas"), ctx = canvas.getContext('2d')
+canvas.addEventListener("click", function(e){
+ if (e.shiftKey) {
+ shader_index = (shader_index-1 + SHADERS.length) % SHADERS.length
+ }
+ else {
+ shader_index = (shader_index+1) % SHADERS.length
+ }
+ console.log("using shader", SHADERS[shader_index].name)
+ Photo.set_shade_fn(SHADERS[shader_index].shader)
+})
+
function toCanvas(rows){
var wpx = 6, hpx = 12
var rgb_colors = Photo.colors.map(function(c){ return "rgb(" + c + ")" })
@@ -156,8 +233,6 @@ function toCanvas(rows){
})
})
height_span.innerHTML = rows.length
- image_style.innerHTML = ""
- image_style.appendChild(canvas)
}
timer_el.addEventListener("click", function(){
var secs = 5;
@@ -173,4 +248,3 @@ timer_el.addEventListener("click", function(){
})()
})
</script>
-