It is currently Tue Jul 02, 2024 2:16 am


All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: Composed in GIMP
PostPosted: Sun Mar 05, 2023 10:56 am  (#1) 
Offline
Script Coder
User avatar

Joined: May 07, 2014
Posts: 4001
Location: Canada
Hi,
I just wanted to share this, which was composed in GIMP (after copying many copies of variations/random wiggles and setting some copies to be partially transparent).
source image: https://unsplash.com/photos/03aPGv9C88k (by Markus Spiske).
This image was traced using a js/html file/program i wrote.
After doodling/tracing the image, i just right click the right side canvas and "Copy Image" and paste into GIMP as new layer (repeat it like 5 times) and add a white background since all canvas work in html is defaulted as transparent if not drawn on.
Image

Okay, so now that you've looked at the end result, here's a video capture of some of the process
www.youtube.com Video from : www.youtube.com


Instructions to use the html/javascript program:
Click and drag on left canvas to draw.
Click on a color up top to select that color.
Click anywhere on the black triangle to set brush size to the height of black triangle (where you click) so if you click to far right of triangle the brush size will be set to really big and vice versa.
Toggle checkboxes to see effect after you've doodle/traced some art.
Enter a local location of image file (.jpg) or url to image and click "Load Image" to load that image on left canvas (in order for you see to trace/doodle).

That's it play around.
Here's the code for the html/js file (just copy it and save it as a .html file [for example: tracer.html] and open it with your browser).
<html>
<script type="text/javascript">
colors = [["1","Blue Green","#199ebd"],
["2","Black","#232323"],
["3","Blue Violet","#7366bd"],
["4","Violet(Purple)","#926eae"],
["5","Green","#1cac78"],
["6","Blue","#1f75fe"],
["7","Yellow Green","#c5e384"],
["8","White","#ededed"],
["9","Yellow","#fce883"],
["10","Carnation Pink","#ffaacc"],
["11","Yellow Orange","#ffb653"],
["12","Red","#ee204d"],
["13","Brown","#b5674d"],
["14","Orange","#ff7538"],
["15","Red Orange","#ff5349"],
["16","Red Violet","#c0448f"],
["17","Gray","#95918c"],
["18","Cerulean","#1dacd6"],
["19","Indigo","#5d76cb"],
["20","Green Yellow","#f0e891"],
["21","Dandelion","#fddb6d"],
["22","Apricot","#fdd9b5"],
["23","Violet Red","#f75394"],
["24","Scarlet","#fc2847"],
["25","Wisteria","#cda4de"],
["26","Sky Blue","#80daeb"],
["27","Cadet Blue","#b0b7c6"],
["28","Timberwolf","#dbd7d2"],
["29","Melon","#fdbcb4"],
["30","Peach","#ffcfab"],
["31","Tan","#faa76c"],
["32","Chestnut","#bc5d58"],
];
    var canvas,canvas2, ctx,ctx2, flag,canvas1,ctx1 = false,
        prevX = 0,
        currX = 0,
        prevY = 0,
        currY = 0,
        dot_flag = false;
    var color = "#000000",
        lineWidth = 2;
    base = 70;
    top = 10;   
    function drawcolors(){
        for (var x=0;x<16;x++){
            ctx1.fillStyle = colors[x][2];
            ctx1.fillRect(x*40,0,40,40);
        }   
        for (var x=16;x<32;x++){
            ctx1.fillStyle = colors[x][2];
            ctx1.fillRect((x-16)*40,40,40,40);
        }   
        ctx1.fillStyle = "rgb(0,0,0)";
        ctx1.beginPath();
       
        ctx1.lineTo(640,70);
        ctx1.lineTo(700,10);
        ctx1.lineTo(700,70);
        ctx1.lineTo(640,70);
        ctx1.closePath();
        ctx1.fill();
    }
    img = 0;
    function init() {
        canvas1 = document.getElementById('canvas');
        ctx1 = canvas1.getContext("2d");
        canvas1.addEventListener("mousedown", function (e) {
            choosexy('down', e)
        }, false);

        canvas = document.getElementById('can');
        canvas2 = document.getElementById('can2');
        ctx = canvas.getContext("2d");
        ctx2 = canvas2.getContext("2d");
        img = document.getElementById("img");
        canvas.width = img.width;
        canvas.height = img.height;
        canvas2.width = canvas.width;
        canvas2.height = canvas.height;
        w = canvas.width;
        h = canvas.height;
        ph = document.getElementById('ph');
        ph.style.top = parseInt(canvas.height)+100+"px";
        canvas2.style.left = parseInt(canvas.width)+10+"px";
        ctx.lineCap = "round";
        ctx2.lineCap = "round";
        canvas.addEventListener("mousemove", function (e) {
            findxy('move', e)
        }, false);
        canvas.addEventListener("mousedown", function (e) {
            findxy('down', e)
        }, false);
        canvas.addEventListener("mouseup", function (e) {
            findxy('up', e)
        }, false);
        canvas.addEventListener("mouseout", function (e) {
            findxy('out', e)
        }, false);
        drawcolors();
    }
    strokes = [];
    strokecount = 0;
    function shuffle_(array) {
        let currentIndex = array.length,  randomIndex;
    // While there remain elements to shuffle.
      while (currentIndex != 0) {

    // Pick a remaining element.
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;

    // And swap it with the current element.
        [array[currentIndex], array[randomIndex]] = [   
        array[randomIndex], array[currentIndex]];
    }
    return array;
    }
    function componentToHex(c) {
  var hex = c.toString(16);
  return hex.length == 1 ? "0" + hex : hex;
}

function rgbToHex(r, g, b) {
  return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
function rgbStrToHex(rgbstring){
    rgb = rgbstring;
    //rgb = "rgb(0,128,255)"
    values = rgb.slice(4,-1).split(',');
return rgbToHex(parseInt(values[0]),parseInt(values[1]),parseInt(values[2]));
}
const hexToRgb = hex =>
  hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i
             ,(m, r, g, b) => '#' + r + r + g + g + b + b)
    .substring(1).match(/.{2}/g)
    .map(x => parseInt(x, 16));
     function width_(array){
       halfsize = array.length/2.0;
       currentlw = array[0][5];
       
       for (var i=0;i<array.length;i++){

             angle = (90-Math.abs((halfsize)-i)/(halfsize)*90.0)/360.0*2.0*3.1415;
             thislw = currentlw * 0.1 + Math.sin(angle)*currentlw*1.0;
             array[i][5] = thislw;
             c = array[i][4];
                currentc = hexToRgb(c);
                //document.getElementById('debug').innerHTML += currentc + ",";
                r = parseInt(currentc[0]);
                g = parseInt(currentc[1]);
                b = parseInt(currentc[2]);
           
            maxbrightvalue = Math.max(r,g,b);
            ubound = (Math.min(maxbrightvalue*1.3,255.0))/maxbrightvalue;
            lbound = 0.8;
            fraction = ubound - Math.sin(angle)*(ubound-lbound);
             thisr = parseInt(r*fraction);
             thisg = parseInt(g*fraction);
             thisb = parseInt(b*fraction);
             
             array[i][7] = thisr;
             array[i][8] = thisg;
             array[i][9] = thisb;
       }
       
       return array;
    }
    function strokeShuffle(){
        strokes2 = [];
        lsc = -1;
        thisstrokes = [];
        for (var i=0;i<strokes.length;i++){
            sc = strokes[i][6];
            if (sc!=lsc){
                if (thisstrokes.length > 0){
                    thisstrokes = shuffle_(thisstrokes.slice());
                    for (var j=0;j<thisstrokes.length;j++){
                        strokes2.push(thisstrokes[j].slice());
                    }
                }
                thisstrokes = [];
                lsc = sc;
            }
            thisstrokes.push(strokes[i].slice());
        }
        if (thisstrokes.length > 0){
            thisstrokes = shuffle_(thisstrokes.slice());
            for (var j=0;j<thisstrokes.length;j++){
                strokes2.push(thisstrokes[j].slice());
                }
        }
        return strokes2;
    }
    function strokeWidth(){
        strokes2 = [];
        lsc = -1;
        thisstrokes = [];
        for (var i=0;i<strokes.length;i++){
            sc = strokes[i][6];
            if (sc!=lsc){
                if (thisstrokes.length > 0){
                    thisstrokes = width_(thisstrokes.slice());
                    for (var j=0;j<thisstrokes.length;j++){
                        strokes2.push(thisstrokes[j].slice());
                    }
                }
                thisstrokes = [];
                lsc = sc;
            }
            thisstrokes.push(strokes[i].slice());
        }
        if (thisstrokes.length > 0){
            thisstrokes = width_(thisstrokes.slice());
            for (var j=0;j<thisstrokes.length;j++){
                strokes2.push(thisstrokes[j].slice());
                }
        }
        return strokes2;
    }
    function draw2(){
        ctx2.clearRect(0, 0, w, h);
        lc = -1;
        llw = -1;
        lsc = -1;
        // if (document.getElementById('shuffle').checked){
        //     strokes2 = strokeShuffle(strokes.slice());
        // }else{
            //strokes2 = strokes.slice();
            strokes2 = strokeWidth(strokes.slice());
        // }
        for (var i=0;i<strokes2.length;i++){
                dx1 = strokes2[i][0];
                dy1 = strokes2[i][1];
                dx2 = strokes2[i][2];
                dy2 = strokes2[i][3];
                dc = strokes2[i][4];
                lw = strokes2[i][5];
                sc = strokes2[i][6];
                r = strokes2[i][7];
                g = strokes2[i][8];
                b = strokes2[i][9];
            if (document.getElementById('offsetly').checked){
                ox = (dx2-dx1) * (Math.random()*0.4+0.8)/2.0;
                oy = (dy2-dy1) * (Math.random()*0.4+0.8)/2.0;
                cx = (dx2+dx1)/2.0;
                cy = (dy2+dy1)/2.0;
                dx1 = cx - ox;
                dy1 = cy - oy;
                dx2 = cx + ox;
                dy2 = cy + oy;
            }
            //if ((lc != dc) || (llw != lw) ||) { //if it's the first stroke we set lx and ly to start there
            if (lsc != sc) { //if different stroke count
               lx = dx1;
               ly = dy1;
               lc = dc;
               llw = lw;
               lsc = sc;
            } 
            if (Math.random()>=0.0) {
                if (document.getElementById('offsetly').checked){
                    nx = dx2-dx1;
                    ny = dy2-dy1;
                    dx1 = lx;
                    dy1 = ly;
                    dx2 = lx+nx;
                    dy2 = ly+ny;
                }
                ctx2.beginPath();
                ctx2.moveTo(dx1,dy1);
                ctx2.lineTo(dx2,dy2);
                //ctx2.strokeStyle = dc;
                ctx2.strokeStyle = "rgb("+r+","+g+","+b+")";
                ctx2.lineWidth = lw;
                ctx2.stroke();
                ctx2.closePath();
                lx = dx2;
                ly = dy2;
            }     
            // if (Math.random()>0.5) {
            //     if (document.getElementById('offsetly').checked){
            //         nx = dx2-dx1;
            //         ny = dy2-dy1;
            //         dx1 = lx;
            //         dy1 = ly;
            //         dx2 = lx+nx;
            //         dy2 = ly+ny;
            //     }
            //     ctx2.beginPath();
            //     ctx2.moveTo(dx1,dy1);
            //     ctx2.lineTo(dx2,dy2);
            //     ctx2.strokeStyle = dc;
            //     ctx2.lineWidth = lw;
            //     ctx2.stroke();
            //     ctx2.closePath();
            //     lx = dx2;
            //     ly = dy2;
            // }   
        }
    }
    function draw1(){
        ctx.clearRect(0, 0, w, h);
        for (var i=0;i<strokes.length;i++){
                dx1 = strokes[i][0];
                dy1 = strokes[i][1];
                dx2 = strokes[i][2];
                dy2 = strokes[i][3];
                dc = strokes[i][4];
                lw = strokes[i][5];
                sc = strokes[i][6];
                 ctx.beginPath();
                ctx.moveTo(dx1,dy1);
                ctx.lineTo(dx2,dy2);
                ctx.strokeStyle = dc;
                ctx.lineWidth = lw;
                ctx.stroke();
                ctx.closePath();
        }       
        // ctx.beginPath();
        // ctx.moveTo(prevX, prevY);
        // ctx.lineTo(currX, currY);
        // ctx.strokeStyle = color;
        // ctx.lineWidth = lineWidth;
        // ctx.stroke();
        // ctx.closePath();
    }
    function draw() {

        // ctx.beginPath();
        // ctx.moveTo(prevX, prevY);
        // ctx.lineTo(currX, currY);
        // ctx.strokeStyle = color;
        // ctx.lineWidth = lineWidth;
        // ctx.stroke();
        // ctx.closePath();
        if (color.includes("rgb")){color = rgbStrToHex(color);
                                    } //always turn it into hex
        rgbthis = hexToRgb(color);
       
        strokes.push([prevX,prevY,currX,currY,color,lineWidth,strokecount,rgbthis[0],rgbthis[1],rgbthis[2]]); //save stroke information as we draw
        draw1();
        ctx.globalAlpha=.5;
        ctx.drawImage(img,0,0,canvas.width,canvas.height);
        ctx.globalAlpha=1.0;
        draw2();
    }

    function erase() {
        var m = confirm("Want to clear");
        if (m) {
            strokes = [];
            strokecount = 0;
            ctx.clearRect(0, 0, w, h);
            ctx2.clearRect(0, 0, w, h);
            document.getElementById("canvasimg").style.display = "none";
        }
    }
   
    function save() {
        document.getElementById("canvasimg").style.border = "2px solid";
        var dataURL = canvas.toDataURL();
        document.getElementById("canvasimg").src = dataURL;
        document.getElementById("canvasimg").style.display = "inline";
    }
   
    function choosexy(res, e) {
        if (res == 'down') {
            prevX = currX;
            prevY = currY;
            currX = e.clientX - canvas1.offsetLeft;
            currY = e.clientY - canvas1.offsetTop;
            if (currX < 640){
                pixel = ctx1.getImageData(currX, currY, 1, 1).data;
                color = "rgb("+pixel[0]+","+pixel[1]+","+pixel[2]+")";
            }else{
                lineWidth = (currX - 640)/60 * (60);
            }
        }
    }
   
    function findxy(res, e) {
        if (res == 'down') {
            prevX = currX;
            prevY = currY;
            currX = e.clientX - canvas.offsetLeft;
            currY = e.clientY - canvas.offsetTop;
            flag = true;
            dot_flag = true;
            if (dot_flag) {
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.fillRect(currX, currY, 2, 2);
                ctx.closePath();

                ctx2.beginPath();
                ctx2.fillStyle = color;
                ctx2.fillRect(currX, currY, 2, 2);
                ctx2.closePath();
                dot_flag = false;
            }
        }
        if (res == 'up' || res == "out") {
            flag = false;
            strokecount += 1; //increment stroke count
        }
        if (res == 'move') {
            if (flag) {
                prevX = currX;
                prevY = currY;
                currX = e.clientX - canvas.offsetLeft;
                currY = e.clientY - canvas.offsetTop;
                draw();
            }
        }
    }
    function animate(){
        if (document.getElementById('animate').checked){
            draw2();
        }
    }
    setInterval(animate,100);
    function loadimage(){
        image = document.getElementById("img");
        image.onload = function(){
           
            init();
        }
        image.src = document.getElementById('src').value;
    }
    </script>
    <body onload="init()">
        <canvas id="canvas" width="700" height="80" style="position:absolute;top:0px;left:0px;border:1px solid"></canvas>
        <table><tr><td><img src='seagull.jpg' id='img' width="600px" style="position:absolute;top:80px;left:0px;border:2px solid;"><canvas id="can" width="1200" height="1200" style="position:absolute;top:80px;left:0px;border:2px solid;"></canvas></td><td><canvas id="can2" width="1200" height="960" style="position:absolute;top:80px;left:1200px;border:2px solid;"></td></tr></table><br/>
        <div id='ph' style="position:absolute;top:1100px;left:0%;">
        <input type='submit' value='Clear' onclick='erase()'><br/>
        <input type='checkbox' id='offsetly' value=''>Offsetly Drawn<br/>
        <!-- <input type='checkbox' id='shuffle' value=''>Shuffle Stroke Parts<br/> -->
        <input type='submit' value='Redraw Canvas2' onclick='draw2()'><br/>
        <input type="checkbox" id='animate'>Continuous Redraws<br/>
        Image location/url:<input type='text' id='src' value='seagull.jpg'><input type='submit' onclick='loadimage()' value='Load Image'><br/>
        <div id='debug'></div>
        <hr>
        <div id='donate'>
        The NSI (not so important) stuff: If you find this js/html useful, feel free to use it but if you make money from it (I ask that <br>
        you transfer $1 USD per sale to me through Paypal at oldtran@gmail.com). If you don't use Paypal, then don't worry about it. I understand<br/>
        that there might be fees so maybe save it until you have more than 10 sales then transfer to me once and minus the fee. I would appreciate<br/>
         this and maybe even add features in the future to this existing program.<br/><br/>
        I also ask that you donate $1 per sale to GIMP foundation.<br/><br/>
        I think it's a fair deal, as there is no risk to you for using it for free as much as you please, and only turn around and donate only when you've made sales.<br/>
        </div>
        </div>
</body>
</html>


The NSI (not so important) stuff: If you find this js/html useful, feel free to use it but if you make money from it (I ask that you transfer $1 USD per sale to me through Paypal at oldtran@gmail.com). If you don't use Paypal, then don't worry about it. I understand that there might be fees so maybe save it until you have more than 10 sales then transfer to me once and minus the fee. I would appreciate this and maybe even add features in the future to this existing program.

I also ask that you donate $1 per sale to GIMP foundation.

I think it's a fair deal, as there is no risk to you for using it for free as much as you please, and only turn around and donate only when you've made sales.

_________________
TinT


Last edited by trandoductin on Sun Mar 05, 2023 11:18 am, edited 2 times in total.

Share on Facebook Share on Twitter Share on Orkut Share on Digg Share on MySpace Share on Delicious Share on Technorati
Top
 Post subject: Re: Composed in GIMP
PostPosted: Sun Mar 05, 2023 11:01 am  (#2) 
Offline
Script Coder
User avatar

Joined: May 07, 2014
Posts: 4001
Location: Canada
Here are some other work that I have traced.
Image
Image
Image
Image
Image

_________________
TinT


Top
 Post subject: Re: Composed in GIMP
PostPosted: Sun Mar 05, 2023 8:03 pm  (#3) 
Offline
Script Coder
User avatar

Joined: May 07, 2014
Posts: 4001
Location: Canada
source: Chaoyang building in China - photo by Jimmy Chang (https://unsplash.com/photos/ACt8ycSzpdE).
Traced by me, and overlayed it.
Image

_________________
TinT


Top
 Post subject: Re: Composed in GIMP
PostPosted: Sun Mar 05, 2023 9:29 pm  (#4) 
Offline
Script Coder
User avatar

Joined: May 07, 2014
Posts: 4001
Location: Canada
This one I really like with color variation added to program.

Image

_________________
TinT


Top
 Post subject: Re: Composed in GIMP
PostPosted: Mon Mar 06, 2023 12:58 am  (#5) 
Offline
GimpChat Member
User avatar

Joined: Dec 09, 2018
Posts: 656
Interesting work, thanks for sharing. I like your outcomes.

Gave it a quick try.

Attachment:
lines.png
lines.png [ 262 KiB | Viewed 796 times ]


Top
 Post subject: Re: Composed in GIMP
PostPosted: Mon Mar 06, 2023 6:31 am  (#6) 
Offline
Script Coder
User avatar

Joined: May 07, 2014
Posts: 4001
Location: Canada
That's a very nice look bike :)

_________________
TinT


Top
 Post subject: Re: Composed in GIMP
PostPosted: Mon Mar 06, 2023 10:17 am  (#7) 
Offline
Script Coder
User avatar

Joined: May 07, 2014
Posts: 4001
Location: Canada
Upgraded with reflections/mirrors and grid render features.
Please see video to see the new features
www.youtube.com Video from : www.youtube.com

ImageImage

Here's the code for the upgrade program:
<html>
<script type="text/javascript">
colors = [["1","Blue Green","#199ebd"],
["2","Black","#232323"],
["3","Blue Violet","#7366bd"],
["4","Violet(Purple)","#926eae"],
["5","Green","#1cac78"],
["6","Blue","#1f75fe"],
["7","Yellow Green","#c5e384"],
["8","White","#ededed"],
["9","Yellow","#fce883"],
["10","Carnation Pink","#ffaacc"],
["11","Yellow Orange","#ffb653"],
["12","Red","#ee204d"],
["13","Brown","#b5674d"],
["14","Orange","#ff7538"],
["15","Red Orange","#ff5349"],
["16","Red Violet","#c0448f"],
["17","Gray","#95918c"],
["18","Cerulean","#1dacd6"],
["19","Indigo","#5d76cb"],
["20","Green Yellow","#f0e891"],
["21","Dandelion","#fddb6d"],
["22","Apricot","#fdd9b5"],
["23","Violet Red","#f75394"],
["24","Scarlet","#fc2847"],
["25","Wisteria","#cda4de"],
["26","Sky Blue","#80daeb"],
["27","Cadet Blue","#b0b7c6"],
["28","Timberwolf","#dbd7d2"],
["29","Melon","#fdbcb4"],
["30","Peach","#ffcfab"],
["31","Tan","#faa76c"],
["32","Chestnut","#bc5d58"],
];
    var varyColorBy = 20; //value to vary each color by out of 255 (plus or minus this value). changed by textbox input later
    var canvas,canvas2, ctx,ctx2, flag,canvas1,ctx1 = false,
        prevX = 0,
        currX = 0,
        prevY = 0,
        currY = 0,
        dot_flag = false;
    var color = colors[1][2];
    var lineWidth = 2;
    base = 70;
    top = 10;   
    function drawcolors(){
        ctx1.clearRect(0,0,canvas1.width,canvas1.height)
        for (var x=0;x<16;x++){
            ctx1.fillStyle = colors[x][2];
            ctx1.fillRect(x*40,0,40,40);
        }   
        for (var x=16;x<32;x++){
            ctx1.fillStyle = colors[x][2];
            ctx1.fillRect((x-16)*40,40,40,40);
        }   
        ctx1.fillStyle = "rgb(0,0,0)";
        ctx1.beginPath();
        ctx1.lineTo(640,70);
        ctx1.lineTo(760,10);
        ctx1.lineTo(760,70);
        ctx1.lineTo(640,70);
        ctx1.closePath();
        ctx1.fill();
       
        //draw brush size
        radius = lineWidth/2.0;
        ctx1.globalAlpha=0.5;
        ctx1.beginPath();
        ctx1.fillStyle = "red";
        ctx1.arc(640+lineWidth*2,70-radius,radius, 0, 2 * Math.PI);
        ctx1.fill();
        ctx1.globalAlpha=1.0;
        ctx1.globalCompositeOperation = "xor";
        ctx1.beginPath();
       
        ctx1.arc(640+lineWidth*2,70-radius,radius, 0, 2 * Math.PI);
        ctx1.stroke();
        ctx1.globalCompositeOperation = "source-over";

        //draw brush size with current color
        ctx1.beginPath();
        ctx1.arc(800,40,radius,0,2*Math.PI);
        ctx1.fillStyle = color;
        ctx1.fill();
    }
    img = 0;
    function init() {
        canvas1 = document.getElementById('canvas');
        ctx1 = canvas1.getContext("2d");
        canvas1.addEventListener("mousedown", function (e) {
            choosexy('down', e)
        }, false);

        canvas = document.getElementById('can');
        canvas2 = document.getElementById('can2');
        canvas3 = document.getElementById('can3');

        ctx = canvas.getContext("2d");
        ctx2 = canvas2.getContext("2d");
        ctx3 = canvas3.getContext("2d");
        img = document.getElementById("img");
        canvas.width = img.width;
        canvas.height = img.height;
        canvas2.width = canvas.width;
        canvas2.height = canvas.height;
        canvas3.width = canvas.width;
        canvas3.height = canvas.height;
        w = canvas.width;
        h = canvas.height;
        ph = document.getElementById('ph');
        ph.style.top = parseInt(canvas.height)+100+"px";
        canvas2.style.left = parseInt(canvas.width)+10+"px";
        canvas3.style.left = (parseInt(canvas.width)+10)*2 + "px";

        ctx.lineCap = "round";
        ctx2.lineCap = "round";
        canvas.addEventListener("mousemove", function (e) {
            findxy('move', e)
        }, false);
        canvas.addEventListener("mousedown", function (e) {
            findxy('down', e)
        }, false);
        canvas.addEventListener("mouseup", function (e) {
            findxy('up', e)
        }, false);
        canvas.addEventListener("mouseout", function (e) {
            findxy('out', e)
        }, false);
        drawcolors();
    }
    strokes = [];
    multistrokes = [];
    strokecount = 0;
    function shuffle_(array) {
        let currentIndex = array.length,  randomIndex;
    // While there remain elements to shuffle.
      while (currentIndex != 0) {

    // Pick a remaining element.
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;

    // And swap it with the current element.
        [array[currentIndex], array[randomIndex]] = [   
        array[randomIndex], array[currentIndex]];
    }
    return array;
    }
    function componentToHex(c) {
  var hex = c.toString(16);
  return hex.length == 1 ? "0" + hex : hex;
}

function rgbToHex(r, g, b) {
  return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
function rgbStrToHex(rgbstring){
    rgb = rgbstring;
    //rgb = "rgb(0,128,255)"
    values = rgb.slice(4,-1).split(',');
return rgbToHex(parseInt(values[0]),parseInt(values[1]),parseInt(values[2]));
}
const hexToRgb = hex =>
  hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i
             ,(m, r, g, b) => '#' + r + r + g + g + b + b)
    .substring(1).match(/.{2}/g)
    .map(x => parseInt(x, 16));
     function width_(array){
       halfsize = array.length/2.0;
       currentlw = array[0][5];
       c = array[0][4];
       currentc = hexToRgb(c);
       r = parseInt(currentc[0]);
       g = parseInt(currentc[1]);
       b = parseInt(currentc[2]);
       if (document.getElementById('varycheckbox').checked){ //if it's check we vary random within varycolorby range
           varColorBy = parseInt(document.getElementById('varycolorby').value);
           r = Math.min(255,Math.max(0,r+Math.random()*varColorBy*2-varColorBy));
           g = Math.min(255,Math.max(0,g+Math.random()*varColorBy*2-varColorBy));
           b = Math.min(255,Math.max(0,b+Math.random()*varColorBy*2-varColorBy));
       }
       for (var i=0;i<array.length;i++){
             angle = (90-Math.abs((halfsize)-i)/(halfsize)*90.0)/360.0*2.0*3.1415;
             thislw = currentlw * 0.1 + Math.sin(angle)*currentlw*1.0;
             array[i][5] = thislw;
         
                currentc = hexToRgb(c);
                //document.getElementById('debug').innerHTML += currentc + ",";
           
            if (document.getElementById('varywithinstroke').checked){ //if it's check we vary random within varycolorby range
                r = parseInt(currentc[0]);
                g = parseInt(currentc[1]);
                b = parseInt(currentc[2]);
                varColorBy = parseInt(document.getElementById('varycolorby').value);
                r = Math.min(255,Math.max(0,r+Math.random()*varColorBy*2-varColorBy));
                g = Math.min(255,Math.max(0,g+Math.random()*varColorBy*2-varColorBy));
                b = Math.min(255,Math.max(0,b+Math.random()*varColorBy*2-varColorBy));
            }
           
            maxbrightvalue = Math.max(r,g,b);
            ubound = (Math.min(maxbrightvalue*1.3,255.0))/maxbrightvalue;
            lbound = 0.8;
            fraction = ubound - Math.sin(angle)*(ubound-lbound);
             thisr = parseInt(r*fraction);
             thisg = parseInt(g*fraction);
             thisb = parseInt(b*fraction);
             
             array[i][7] = thisr;
             array[i][8] = thisg;
             array[i][9] = thisb;
       }
       
       return array;
    }

    function angleOf(cx, cy, ex, ey) {//returns angle in degrees
        var dy = ey - cy;
        var dx = ex - cx;
        var theta = Math.atan2(dy, dx); // range (-PI, PI]
        //theta *= 180 / Math.PI; // rads to degs, range (-180, 180]
        //if (theta < 0) theta = 360 + theta; // range [0, 360)
        return theta;
    }
   
    function strokeShuffle(){
        strokes2 = [];
        lsc = -1;
        thisstrokes = [];
        for (var i=0;i<strokes.length;i++){
            sc = strokes[i][6];
            if (sc!=lsc){
                if (thisstrokes.length > 0){
                    thisstrokes = shuffle_(thisstrokes.slice());
                    for (var j=0;j<thisstrokes.length;j++){
                        strokes2.push(thisstrokes[j].slice());
                    }
                }
                thisstrokes = [];
                lsc = sc;
            }
            thisstrokes.push(strokes[i].slice());
        }
        if (thisstrokes.length > 0){
            thisstrokes = shuffle_(thisstrokes.slice());
            for (var j=0;j<thisstrokes.length;j++){
                strokes2.push(thisstrokes[j].slice());
                }
        }
        return strokes2;
    }
    function strokeWidth(strokes){
        strokes2 = [];
        lsc = -1;
        thisstrokes = [];
        for (var i=0;i<strokes.length;i++){
            sc = strokes[i][6];
            if (sc!=lsc || i == 0){
                if (thisstrokes.length > 0){
                    thisstrokes = width_(thisstrokes.slice());
                    for (var j=0;j<thisstrokes.length;j++){
                        strokes2.push(thisstrokes[j].slice());
                    }
                }
                thisstrokes = [];
                lsc = sc;
            }
            thisstrokes.push(strokes[i].slice());
        }
        if (thisstrokes.length > 0){
            thisstrokes = width_(thisstrokes.slice());
            for (var j=0;j<thisstrokes.length;j++){
                strokes2.push(thisstrokes[j].slice());
                }
        }
        return strokes2;
    }
    function draw2(){
        ctx2.clearRect(0, 0, w, h);
        for (var s=-1;s<multistrokes.length;s++){
            lc = -1;
            llw = -1;
            lsc = -1;
            //strokes2 = strokeWidth(strokes.slice());
            if (s==-1){
                strokes2 = strokeWidth(strokes.slice());
            }else{
                strokes2 = strokeWidth(multistrokes[s].slice());
            }

            for (var i=0;i<strokes2.length;i++){
                    dx1 = strokes2[i][0];
                    dy1 = strokes2[i][1];
                    dx2 = strokes2[i][2];
                    dy2 = strokes2[i][3];
                    dc = strokes2[i][4];
                    lw = strokes2[i][5];
                    sc = strokes2[i][6];
                    r = strokes2[i][7];
                    g = strokes2[i][8];
                    b = strokes2[i][9];
                if (document.getElementById('offsetly').checked){
                    ox = (dx2-dx1) * (Math.random()*0.4+0.8)/2.0;
                    oy = (dy2-dy1) * (Math.random()*0.4+0.8)/2.0;
                    cx = (dx2+dx1)/2.0;
                    cy = (dy2+dy1)/2.0;
                    dx1 = cx - ox;
                    dy1 = cy - oy;
                    dx2 = cx + ox;
                    dy2 = cy + oy;
                }
                //if ((lc != dc) || (llw != lw) ||) { //if it's the first stroke we set lx and ly to start there
                if (lsc != sc) { //if different stroke count
                   lx = dx1;
                   ly = dy1;
                   lc = dc;
                   llw = lw;
                   lsc = sc;
                } 
                if (Math.random()>=0.0) {
                    if (document.getElementById('offsetly').checked){
                        nx = dx2-dx1;
                        ny = dy2-dy1;
                        dx1 = lx;
                        dy1 = ly;
                        dx2 = lx+nx;
                        dy2 = ly+ny;
                    }
                    if (document.getElementById('stroketype').value == "1"){ //regular stroke
                        ctx2.beginPath();
                        ctx2.moveTo(dx1,dy1);
                        ctx2.lineTo(dx2,dy2);
                        //ctx2.strokeStyle = dc;
                        ctx2.strokeStyle = "rgb("+r+","+g+","+b+")";
                        ctx2.lineWidth = lw;
                        ctx2.stroke();
                        ctx2.closePath();
                    }else if (document.getElementById('stroketype').value == "2"){ //circles
                        ctx2.beginPath();
                        cx = (dx1+dx2)/2;
                        cy = (dy1+dy1)/2;
                        //ctx2.strokeStyle = dc;
                        ctx2.strokeStyle = "rgb("+r+","+g+","+b+")";
                        //ctx2.lineWidth = lw;
                        ctx2.lineWidth = Math.max(1.0,lw/10.0);
                        ctx2.arc(cx,cy,lw/2.0,0,Math.PI*2);
                        ctx2.stroke();
                        ctx2.closePath();
                    }
                    lx = dx2;
                    ly = dy2;
                }     
            }
        }
    }
    function draw1(){
        ctx.clearRect(0, 0, w, h);
        for (var i=0;i<strokes.length;i++){
                dx1 = strokes[i][0];
                dy1 = strokes[i][1];
                dx2 = strokes[i][2];
                dy2 = strokes[i][3];
                dc = strokes[i][4];
                lw = strokes[i][5];
                sc = strokes[i][6];
                 ctx.beginPath();
                ctx.moveTo(dx1,dy1);
                ctx.lineTo(dx2,dy2);
                ctx.strokeStyle = dc;
                ctx.lineWidth = lw;
                ctx.stroke();
                ctx.closePath();
        }
        if (document.getElementById('reflect').checked){
            for (var j=0;j<multistrokes.length;j++){
                stroke = multistrokes[j];
                for (var i=0;i<stroke.length;i++){
                    dx1 = stroke[i][0];
                    dy1 = stroke[i][1];
                    dx2 = stroke[i][2];
                    dy2 = stroke[i][3];
                    dc = stroke[i][4];
                    lw = stroke[i][5];
                    sc = stroke[i][6];
                     ctx.beginPath();
                    ctx.moveTo(dx1,dy1);
                    ctx.lineTo(dx2,dy2);
                    ctx.strokeStyle = dc;
                    ctx.lineWidth = lw;
                    ctx.stroke();
                    ctx.closePath();
                }             
            }
        }
        // ctx.beginPath();
        // ctx.moveTo(prevX, prevY);
        // ctx.lineTo(currX, currY);
        // ctx.strokeStyle = color;
        // ctx.lineWidth = lineWidth;
        // ctx.stroke();
        // ctx.closePath();
    }
    function draw3(){
        ctx3.globalAlpha = 1.0;
        ctx3.clearRect(0,0,canvas3.width,canvas3.height);
        //ctx3.fillStyle= 'white';
        //ctx3.fillRect(0,0,canvas3.width,canvas3.height);
        for (var i=1;i<=8;i++){
            if (document.getElementById("grid").checked){
                by = parseInt(document.getElementById("byValue").value);
                size = canvas.width/by;
                for (var y=0;y<by;y++){
                    for (var x=0;x<by;x++){
                        draw2();
                        ctx3.globalAlpha = 1.0/i;
                        ctx3.drawImage(canvas2,x*size,y*size,size,size);
                    }
                }
            }else{
                draw2();
                ctx3.globalAlpha = 1.0/i;
                ctx3.drawImage(canvas2,0,0);
            }
        }
    }
    function drawCursor(clear = 0){
        if (clear == 1){
            ctx.clearRect(0,0,canvas.width,canvas.height);
            //redisplay them all before drawing cursor
        //ctx.globalAlpha=1.0;
        //ctx.drawImage(img,0,0,canvas.width,canvas.height);
        draw1();
        ctx.globalAlpha=.5;
        ctx.drawImage(img,0,0,canvas.width,canvas.height);
        ctx.globalAlpha=1.0;
        }
       



        ctx.beginPath();
        ctx.arc(currX,currY,lineWidth/2.0,0,Math.PI*2.0);
        saveLineWith = ctx.lineWidth;
        ctx.lineWidth = 1;
        savestrokeStyle = ctx.strokeStyle;
        ctx.strokeStyle = 'red';
        ctx.globalCompositeOperation = "xor";
        ctx.stroke();
        ctx.globalCompositeOperation = "source-over";
        ctx.strokeStyle = savestrokeStyle;
        ctx.lineWidth = saveLineWith;
    }
    mirrors = 6;
    function reflectthem(mirrors){
        mirrors = parseInt(mirrors);
        reflection = [];
        mx = canvas.width/2.0;
        my = canvas.height/2.0;
        for (var i=0;i<strokes.length;i++){
            reflection.push(strokes[i].slice());
            reflection[i][0] = mx - (reflection[i][0] - mx);
            reflection[i][2] = mx - (reflection[i][2] - mx);
        }
        multistrokes.push(reflection);
        incang = 360.0/mirrors/360.0*2*Math.PI;
        for (var a=1;a<mirrors;a++){
            ref = [];
            for (var i=0;i<strokes.length;i++){
                ref.push(strokes[i].slice());
                p1angle = angleOf(mx,my,ref[i][0],ref[i][1]);
                p2angle = angleOf(mx,my,ref[i][2],ref[i][3]);
                p1radius = ((ref[i][0]-mx)**2+(ref[i][1]-my)**2)**0.5;
                p2radius = ((ref[i][2]-mx)**2+(ref[i][3]-my)**2)**0.5;
                newangle1 = p1angle+a*incang;
                newangle2 = p2angle+a*incang;
                ref[i][0] = mx + p1radius * Math.cos(newangle1);
                ref[i][1] = my + p1radius * Math.sin(newangle1);
                ref[i][2] = mx + p2radius * Math.cos(newangle2);
                ref[i][3] = my + p2radius * Math.sin(newangle2);
            }
            multistrokes.push(ref);
            ref = [];
            for (var i=0;i<strokes.length;i++){
                ref.push(reflection[i].slice());
                p1angle = angleOf(mx,my,ref[i][0],ref[i][1]);
                p2angle = angleOf(mx,my,ref[i][2],ref[i][3]);
                p1radius = ((ref[i][0]-mx)**2+(ref[i][1]-my)**2)**0.5;
                p2radius = ((ref[i][2]-mx)**2+(ref[i][3]-my)**2)**0.5;
                newangle1 = p1angle+a*incang;
                newangle2 = p2angle+a*incang;
                ref[i][0] = mx + p1radius * Math.cos(newangle1);
                ref[i][1] = my + p1radius * Math.sin(newangle1);
                ref[i][2] = mx + p2radius * Math.cos(newangle2);
                ref[i][3] = my + p2radius * Math.sin(newangle2);
            }
            multistrokes.push(ref);
        }
    }
    function draw() {

        // ctx.beginPath();
        // ctx.moveTo(prevX, prevY);
        // ctx.lineTo(currX, currY);
        // ctx.strokeStyle = color;
        // ctx.lineWidth = lineWidth;
        // ctx.stroke();
        // ctx.closePath();
        if (color.includes("rgb")){color = rgbStrToHex(color);
                                    } //always turn it into hex
        rgbthis = hexToRgb(color);
       
        strokes.push([prevX,prevY,currX,currY,color,lineWidth,strokecount,rgbthis[0],rgbthis[1],rgbthis[2]]); //save stroke information as we draw
        if (document.getElementById('reflect').checked){
            multistrokes = [];
            mirrors = parseInt(document.getElementById('mirrors').value);
            reflectthem(mirrors);
        }else{
            multistrokes = [];
        }
        draw1();
        drawCursor();

        ctx.globalAlpha=.5;
        ctx.drawImage(img,0,0,canvas.width,canvas.height);
        ctx.globalAlpha=1.0;
        draw2();
    }
   

    function erase() {
        var m = confirm("Want to clear");
        if (m) {
            strokes = [];
            strokecount = 0;
            ctx.clearRect(0, 0, w, h);
            ctx2.clearRect(0, 0, w, h);
            document.getElementById("canvasimg").style.display = "none";
        }
    }
   
    function save() {
        document.getElementById("canvasimg").style.border = "2px solid";
        var dataURL = canvas.toDataURL();
        document.getElementById("canvasimg").src = dataURL;
        document.getElementById("canvasimg").style.display = "inline";
    }
   
    function choosexy(res, e) {
        if (res == 'down') {
            prevX = currX;
            prevY = currY;
            currX = e.clientX - canvas1.offsetLeft;
            currY = e.clientY - canvas1.offsetTop;
            if (currX < 640){
                pixel = ctx1.getImageData(currX, currY, 1, 1).data;
                color = "rgb("+pixel[0]+","+pixel[1]+","+pixel[2]+")";
            }else{
                lineWidth = (currX - 640)/120 * (60);
            }
            drawcolors();
        }
    }
   
    function findxy(res, e) {
        if (res == 'down') {
            prevX = currX;
            prevY = currY;
            currX = e.clientX - canvas.offsetLeft;
            currY = e.clientY - canvas.offsetTop;
            flag = true;
            dot_flag = true;
            if (dot_flag) {
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.fillRect(currX, currY, 2, 2);
                ctx.closePath();

                ctx2.beginPath();
                ctx2.fillStyle = color;
                ctx2.fillRect(currX, currY, 2, 2);
                ctx2.closePath();
                dot_flag = false;
            }
        }
        if (res == 'up' || res == "out") {
            flag = false;
            strokecount += 1; //increment stroke count
        }
        if (res == 'move') {
            if (flag) {
                prevX = currX;
                prevY = currY;
                currX = e.clientX - canvas.offsetLeft;
                currY = e.clientY - canvas.offsetTop;
                draw();
            }else{
                currX = e.clientX - canvas.offsetLeft;
                currY = e.clientY - canvas.offsetTop;
                drawCursor(1);
            }
        }
    }
    function animate(){
        if (document.getElementById('animate').checked){
            draw2();
        }
    }
    setInterval(animate,100);
    function loadimage(){
        image = document.getElementById("img");
        image.onload = function(){
           
            init();
        }
        image.src = document.getElementById('src').value;
    }
    function save(){
        localStorage.setItem("tracer_strokes", JSON.stringify(strokes));
    }
    function load(){
        strokes = JSON.parse(localStorage.getItem("tracer_strokes"));
    }
    </script>
    <body onload="init()">
        <canvas id="canvas" width="840" height="80" style="position:absolute;top:0px;left:0px;border:1px solid"></canvas>
        <table><tr><td><img src='square.jpg' id='img' width="2000px" style="position:absolute;top:80px;left:0px;border:2px solid;"><canvas id="can" width="1200" height="1200" style="position:absolute;top:80px;left:0px;border:2px solid;"></canvas></td><td><canvas id="can2" width="1200" height="960" style="position:absolute;top:80px;left:1200px;border:2px solid;"></td>
            <td><canvas id="can3" width="1200" height="960" style="position:absolute;top:80px;left:2400px;border:2px solid;"></td></tr></table><br/>
        <div id='ph' style="position:absolute;top:1100px;left:0%;">
        <input type='submit' value='Clear' onclick='erase()'><br/>
        <input type='checkbox' id='offsetly' value=''>Offsetly Drawn<br/>
        <!-- <input type='checkbox' id='shuffle' value=''>Shuffle Stroke Parts<br/> -->
        <input type="checkbox" id='animate' checked>Continuous Redraws<br/>
        <input type="checkbox" id='varycheckbox' checked>Vary Color Channels by <input type='text' id='varycolorby' value='50' size=3>/255 - <input type="checkbox" id='varywithinstroke'>Vary Within Strokes<br/>
       
        Image location/url:<input type='text' id='src' value='seagull.jpg'><input type='submit' onclick='loadimage()' value='Load Image'><br/>
        <select id="stroketype"><option value="1" selected>Regular Stroke</option>
                               <option value="2">Circles</option>
        </select>
        <input type='checkbox' id='reflect' checked>Reflect <input type='text' id='mirrors' value='6' size=3> Mirrors<br/>
        <input type='checkbox' id='grid' checked>Grid (of Multiples) of <input type='text' id='byValue' value='4' size=3> n by n Value<br/><br/>
        <input type='submit' value='Redraw Canvas3' onclick='draw3()'><br/>
        <br/>
        <input type='submit' value='Save to Local Storage' onclick='save()'><input type='submit' value='Load from Local Storage' onclick='load()'><br/>

        <div id='debug'></div>
        <hr>
        <div id='donate'>
        The NSI (not so important) stuff: If you find this js/html useful, feel free to use it but if you make money from it (I ask that <br>
        you transfer $1 USD per sale to me through Paypal at oldtran@gmail.com). If you don't use Paypal, then don't worry about it. I understand<br/>
        that there might be fees so maybe save it until you have more than 10 sales then transfer to me once and minus the fee. I would appreciate<br/>
         this and maybe even add features in the future to this existing program.<br/><br/>
        I also ask that you donate $1 per sale to GIMP foundation.<br/><br/>
        I think it's a fair deal, as there is no risk to you for using it for free as much as you please, and only turn around and donate only when you've made sales.<br/>
        </div>
        </div>
</body>
</html>


_________________
TinT


Top
 Post subject: Re: Composed in GIMP
PostPosted: Tue Mar 07, 2023 12:45 am  (#8) 
Offline
Script Coder
User avatar

Joined: May 07, 2014
Posts: 4001
Location: Canada
I think it looks more interesting to see progression from starting to end.
Image
Here's the new code (along with fix to mouse cursor bug that doesn't draw on right location as well)
<html>
<script type="text/javascript">
colors = [["1","Blue Green","#199ebd"],
["2","Black","#232323"],
["3","Blue Violet","#7366bd"],
["4","Violet(Purple)","#926eae"],
["5","Green","#1cac78"],
["6","Blue","#1f75fe"],
["7","Yellow Green","#c5e384"],
["8","White","#ededed"],
["9","Yellow","#fce883"],
["10","Carnation Pink","#ffaacc"],
["11","Yellow Orange","#ffb653"],
["12","Red","#ee204d"],
["13","Brown","#b5674d"],
["14","Orange","#ff7538"],
["15","Red Orange","#ff5349"],
["16","Red Violet","#c0448f"],
["17","Gray","#95918c"],
["18","Cerulean","#1dacd6"],
["19","Indigo","#5d76cb"],
["20","Green Yellow","#f0e891"],
["21","Dandelion","#fddb6d"],
["22","Apricot","#fdd9b5"],
["23","Violet Red","#f75394"],
["24","Scarlet","#fc2847"],
["25","Wisteria","#cda4de"],
["26","Sky Blue","#80daeb"],
["27","Cadet Blue","#b0b7c6"],
["28","Timberwolf","#dbd7d2"],
["29","Melon","#fdbcb4"],
["30","Peach","#ffcfab"],
["31","Tan","#faa76c"],
["32","Chestnut","#bc5d58"],
];
    var varyColorBy = 20; //value to vary each color by out of 255 (plus or minus this value). changed by textbox input later
    var canvas,canvas2, ctx,ctx2, flag,canvas1,ctx1 = false,
        prevX = 0,
        currX = 0,
        prevY = 0,
        currY = 0,
        dot_flag = false;
    var color = colors[1][2];
    var lineWidth = 2;
    base = 70;
    top = 10;   
    function drawcolors(){
        ctx1.clearRect(0,0,canvas1.width,canvas1.height)
        for (var x=0;x<16;x++){
            ctx1.fillStyle = colors[x][2];
            ctx1.fillRect(x*40,0,40,40);
        }   
        for (var x=16;x<32;x++){
            ctx1.fillStyle = colors[x][2];
            ctx1.fillRect((x-16)*40,40,40,40);
        }   
        ctx1.fillStyle = "rgb(0,0,0)";
        ctx1.beginPath();
        ctx1.lineTo(640,70);
        ctx1.lineTo(760,10);
        ctx1.lineTo(760,70);
        ctx1.lineTo(640,70);
        ctx1.closePath();
        ctx1.fill();
       
        //draw brush size
        radius = lineWidth/2.0;
        ctx1.globalAlpha=0.5;
        ctx1.beginPath();
        ctx1.fillStyle = "red";
        ctx1.arc(640+lineWidth*2,70-radius,radius, 0, 2 * Math.PI);
        ctx1.fill();
        ctx1.globalAlpha=1.0;
        ctx1.globalCompositeOperation = "xor";
        ctx1.beginPath();
       
        ctx1.arc(640+lineWidth*2,70-radius,radius, 0, 2 * Math.PI);
        ctx1.stroke();
        ctx1.globalCompositeOperation = "source-over";

        //draw brush size with current color
        ctx1.beginPath();
        ctx1.arc(800,40,radius,0,2*Math.PI);
        ctx1.fillStyle = color;
        ctx1.fill();
    }
    img = 0;
    function init() {
        canvas1 = document.getElementById('canvas');
        ctx1 = canvas1.getContext("2d");
        canvas1.addEventListener("mousedown", function (e) {
            choosexy('down', e)
        }, false);

        canvas = document.getElementById('can');
        canvas2 = document.getElementById('can2');
        canvas3 = document.getElementById('can3');

        ctx = canvas.getContext("2d");
        ctx2 = canvas2.getContext("2d");
        ctx3 = canvas3.getContext("2d");
        img = document.getElementById("img");
        canvas.width = img.width;
        canvas.height = img.height;
        canvas2.width = canvas.width;
        canvas2.height = canvas.height;
        canvas3.width = canvas.width;
        canvas3.height = canvas.height;
        w = canvas.width;
        h = canvas.height;
        ph = document.getElementById('ph');
        ph.style.top = parseInt(canvas.height)+100+"px";
        canvas2.style.left = parseInt(canvas.width)+10+"px";
        canvas3.style.left = (parseInt(canvas.width)+10)*2 + "px";

        ctx.lineCap = "round";
        ctx2.lineCap = "round";
        canvas.addEventListener("mousemove", function (e) {
            findxy('move', e)
        }, false);
        canvas.addEventListener("mousedown", function (e) {
            findxy('down', e)
        }, false);
        canvas.addEventListener("mouseup", function (e) {
            findxy('up', e)
        }, false);
        canvas.addEventListener("mouseout", function (e) {
            findxy('out', e)
        }, false);
        drawcolors();
    }
    strokes = [];
    multistrokes = [];
    strokecount = -1;
    function shuffle_(array) {
        let currentIndex = array.length,  randomIndex;
    // While there remain elements to shuffle.
      while (currentIndex != 0) {

    // Pick a remaining element.
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;

    // And swap it with the current element.
        [array[currentIndex], array[randomIndex]] = [   
        array[randomIndex], array[currentIndex]];
    }
    return array;
    }
    function componentToHex(c) {
  var hex = c.toString(16);
  return hex.length == 1 ? "0" + hex : hex;
}

function rgbToHex(r, g, b) {
  return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
function rgbStrToHex(rgbstring){
    rgb = rgbstring;
    //rgb = "rgb(0,128,255)"
    values = rgb.slice(4,-1).split(',');
return rgbToHex(parseInt(values[0]),parseInt(values[1]),parseInt(values[2]));
}
const hexToRgb = hex =>
  hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i
             ,(m, r, g, b) => '#' + r + r + g + g + b + b)
    .substring(1).match(/.{2}/g)
    .map(x => parseInt(x, 16));
     function width_(array){
       halfsize = array.length/2.0;
       currentlw = array[0][5];
       c = array[0][4];
       currentc = hexToRgb(c);
       r = parseInt(currentc[0]);
       g = parseInt(currentc[1]);
       b = parseInt(currentc[2]);
       if (document.getElementById('varycheckbox').checked){ //if it's check we vary random within varycolorby range
           varColorBy = parseInt(document.getElementById('varycolorby').value);
           r = Math.min(255,Math.max(0,r+Math.random()*varColorBy*2-varColorBy));
           g = Math.min(255,Math.max(0,g+Math.random()*varColorBy*2-varColorBy));
           b = Math.min(255,Math.max(0,b+Math.random()*varColorBy*2-varColorBy));
       }
       for (var i=0;i<array.length;i++){
             angle = (90-Math.abs((halfsize)-i)/(halfsize)*90.0)/360.0*2.0*3.1415;
             thislw = currentlw * 0.1 + Math.sin(angle)*currentlw*1.0;
             array[i][5] = thislw;
         
                currentc = hexToRgb(c);
                //document.getElementById('debug').innerHTML += currentc + ",";
           
            if (document.getElementById('varywithinstroke').checked){ //if it's check we vary random within varycolorby range
                r = parseInt(currentc[0]);
                g = parseInt(currentc[1]);
                b = parseInt(currentc[2]);
                varColorBy = parseInt(document.getElementById('varycolorby').value);
                r = Math.min(255,Math.max(0,r+Math.random()*varColorBy*2-varColorBy));
                g = Math.min(255,Math.max(0,g+Math.random()*varColorBy*2-varColorBy));
                b = Math.min(255,Math.max(0,b+Math.random()*varColorBy*2-varColorBy));
            }
           
            maxbrightvalue = Math.max(r,g,b);
            ubound = (Math.min(maxbrightvalue*1.3,255.0))/maxbrightvalue;
            lbound = 0.8;
            fraction = ubound - Math.sin(angle)*(ubound-lbound);
             thisr = parseInt(r*fraction);
             thisg = parseInt(g*fraction);
             thisb = parseInt(b*fraction);
             
             array[i][7] = thisr;
             array[i][8] = thisg;
             array[i][9] = thisb;
       }
       
       return array;
    }

    function angleOf(cx, cy, ex, ey) {//returns angle in degrees
        var dy = ey - cy;
        var dx = ex - cx;
        var theta = Math.atan2(dy, dx); // range (-PI, PI]
        //theta *= 180 / Math.PI; // rads to degs, range (-180, 180]
        //if (theta < 0) theta = 360 + theta; // range [0, 360)
        return theta;
    }
   
    function strokeShuffle(){
        strokes2 = [];
        lsc = -1;
        thisstrokes = [];
        for (var i=0;i<strokes.length;i++){
            sc = strokes[i][6];
            if (sc!=lsc){
                if (thisstrokes.length > 0){
                    thisstrokes = shuffle_(thisstrokes.slice());
                    for (var j=0;j<thisstrokes.length;j++){
                        strokes2.push(thisstrokes[j].slice());
                    }
                }
                thisstrokes = [];
                lsc = sc;
            }
            thisstrokes.push(strokes[i].slice());
        }
        if (thisstrokes.length > 0){
            thisstrokes = shuffle_(thisstrokes.slice());
            for (var j=0;j<thisstrokes.length;j++){
                strokes2.push(thisstrokes[j].slice());
                }
        }
        return strokes2;
    }
    function strokeWidth(strokes){
        strokes2 = [];
        lsc = -1;
        thisstrokes = [];
        for (var i=0;i<strokes.length;i++){
            sc = strokes[i][6];
            if (sc!=lsc || i == 0){
                if (thisstrokes.length > 0){
                    thisstrokes = width_(thisstrokes.slice());
                    for (var j=0;j<thisstrokes.length;j++){
                        strokes2.push(thisstrokes[j].slice());
                    }
                }
                thisstrokes = [];
                lsc = sc;
            }
            thisstrokes.push(strokes[i].slice());
        }
        if (thisstrokes.length > 0){
            thisstrokes = width_(thisstrokes.slice());
            for (var j=0;j<thisstrokes.length;j++){
                strokes2.push(thisstrokes[j].slice());
                }
        }
        return strokes2;
    }
    function draw2(){
        ctx2.clearRect(0, 0, w, h);
        for (var s=-1;s<multistrokes.length;s++){
            lc = -1;
            llw = -1;
            lsc = -1;
            //strokes2 = strokeWidth(strokes.slice());
            if (s==-1){
                strokes2 = strokeWidth(strokes.slice());
            }else{
                strokes2 = strokeWidth(multistrokes[s].slice());
            }

            for (var i=0;i<strokes2.length;i++){
                    dx1 = strokes2[i][0];
                    dy1 = strokes2[i][1];
                    dx2 = strokes2[i][2];
                    dy2 = strokes2[i][3];
                    dc = strokes2[i][4];
                    lw = strokes2[i][5];
                    sc = strokes2[i][6];
                    r = strokes2[i][7];
                    g = strokes2[i][8];
                    b = strokes2[i][9];
                if (document.getElementById('offsetly').checked){
                    ox = (dx2-dx1) * (Math.random()*0.4+0.8)/2.0;
                    oy = (dy2-dy1) * (Math.random()*0.4+0.8)/2.0;
                    cx = (dx2+dx1)/2.0;
                    cy = (dy2+dy1)/2.0;
                    dx1 = cx - ox;
                    dy1 = cy - oy;
                    dx2 = cx + ox;
                    dy2 = cy + oy;
                }
                //if ((lc != dc) || (llw != lw) ||) { //if it's the first stroke we set lx and ly to start there
                if (lsc != sc) { //if different stroke count
                   lx = dx1;
                   ly = dy1;
                   lc = dc;
                   llw = lw;
                   lsc = sc;
                } 
                if (Math.random()>=0.0) {
                    if (document.getElementById('offsetly').checked){
                        nx = dx2-dx1;
                        ny = dy2-dy1;
                        dx1 = lx;
                        dy1 = ly;
                        dx2 = lx+nx;
                        dy2 = ly+ny;
                    }
                    if (document.getElementById('stroketype').value == "1"){ //regular stroke
                        ctx2.beginPath();
                        ctx2.moveTo(dx1,dy1);
                        ctx2.lineTo(dx2,dy2);
                        //ctx2.strokeStyle = dc;
                        ctx2.strokeStyle = "rgb("+r+","+g+","+b+")";
                        ctx2.lineWidth = lw;
                        ctx2.stroke();
                        ctx2.closePath();
                    }else if (document.getElementById('stroketype').value == "2"){ //circles
                        ctx2.beginPath();
                        cx = (dx1+dx2)/2;
                        cy = (dy1+dy1)/2;
                        //ctx2.strokeStyle = dc;
                        ctx2.strokeStyle = "rgb("+r+","+g+","+b+")";
                        //ctx2.lineWidth = lw;
                        ctx2.lineWidth = Math.max(1.0,lw/10.0);
                        ctx2.arc(cx,cy,lw/2.0,0,Math.PI*2);
                        ctx2.stroke();
                        ctx2.closePath();
                    }
                    lx = dx2;
                    ly = dy2;
                }     
            }
        }
    }
    function draw1(){
        ctx.clearRect(0, 0, w, h);
        for (var i=0;i<strokes.length;i++){
                dx1 = strokes[i][0];
                dy1 = strokes[i][1];
                dx2 = strokes[i][2];
                dy2 = strokes[i][3];
                dc = strokes[i][4];
                lw = strokes[i][5];
                sc = strokes[i][6];
                 ctx.beginPath();
                ctx.moveTo(dx1,dy1);
                ctx.lineTo(dx2,dy2);
                ctx.strokeStyle = dc;
                ctx.lineWidth = lw;
                ctx.stroke();
                ctx.closePath();
        }
        if (document.getElementById('reflect').checked){
            for (var j=0;j<multistrokes.length;j++){
                stroke = multistrokes[j];
                for (var i=0;i<stroke.length;i++){
                    dx1 = stroke[i][0];
                    dy1 = stroke[i][1];
                    dx2 = stroke[i][2];
                    dy2 = stroke[i][3];
                    dc = stroke[i][4];
                    lw = stroke[i][5];
                    sc = stroke[i][6];
                     ctx.beginPath();
                    ctx.moveTo(dx1,dy1);
                    ctx.lineTo(dx2,dy2);
                    ctx.strokeStyle = dc;
                    ctx.lineWidth = lw;
                    ctx.stroke();
                    ctx.closePath();
                }             
            }
        }
        // ctx.beginPath();
        // ctx.moveTo(prevX, prevY);
        // ctx.lineTo(currX, currY);
        // ctx.strokeStyle = color;
        // ctx.lineWidth = lineWidth;
        // ctx.stroke();
        // ctx.closePath();
    }
    function draw3(){
        ctx3.globalAlpha = 1.0;
        ctx3.clearRect(0,0,canvas3.width,canvas3.height);
        //ctx3.fillStyle= 'white';
        //ctx3.fillRect(0,0,canvas3.width,canvas3.height);
        progression = 0;
        if (document.getElementById("grid").checked && document.getElementById("progression").checked){
            by = parseInt(document.getElementById("byValue").value);
            progressions = by * by;
            progression = 1;
            p = []; //progressions
            savedstrokes = strokes.slice();
            for (var i=1;i<=progressions;i++){
                p.push(strokes.slice(0,Math.round(strokes.length/progressions*i)));
            }
        }
               
        for (var i=1;i<=8;i++){
            if (document.getElementById("grid").checked){
                size = canvas.width/by;
                n = 0;
                for (var y=0;y<by;y++){
                    for (var x=0;x<by;x++){
                        if (progression==1){
                            strokes = p[n].slice();
                            draw(0); //to calculate multi strokes
                        }
                        n+=1;
                        draw2();
                        ctx3.globalAlpha = 1.0/i;
                        ctx3.drawImage(canvas2,x*size,y*size,size,size);
                    }
                }
            }else{
                draw2();
                ctx3.globalAlpha = 1.0/i;
                ctx3.drawImage(canvas2,0,0);
            }
        }
        if (progression==1){
            strokes = savedstrokes.slice();
        }
    }
    function drawCursor(clear = 0){
        if (clear == 1){
            ctx.clearRect(0,0,canvas.width,canvas.height);
            //redisplay them all before drawing cursor
        //ctx.globalAlpha=1.0;
        //ctx.drawImage(img,0,0,canvas.width,canvas.height);
        draw1();
        ctx.globalAlpha=.5;
        ctx.drawImage(img,0,0,canvas.width,canvas.height);
        ctx.globalAlpha=1.0;
        }
       



        ctx.beginPath();
        ctx.arc(currX,currY,lineWidth/2.0,0,Math.PI*2.0);
        saveLineWith = ctx.lineWidth;
        ctx.lineWidth = 1;
        savestrokeStyle = ctx.strokeStyle;
        ctx.strokeStyle = 'red';
        ctx.globalCompositeOperation = "xor";
        ctx.stroke();
        ctx.globalCompositeOperation = "source-over";
        ctx.strokeStyle = savestrokeStyle;
        ctx.lineWidth = saveLineWith;
    }
    mirrors = 6;
    function reflectthem(mirrors){
        mirrors = parseInt(mirrors);
        reflection = [];
        mx = canvas.width/2.0;
        my = canvas.height/2.0;
        for (var i=0;i<strokes.length;i++){
            reflection.push(strokes[i].slice());
            reflection[i][0] = mx - (reflection[i][0] - mx);
            reflection[i][2] = mx - (reflection[i][2] - mx);
        }
        multistrokes.push(reflection);
        incang = 360.0/mirrors/360.0*2*Math.PI;
        for (var a=1;a<mirrors;a++){
            ref = [];
            for (var i=0;i<strokes.length;i++){
                ref.push(strokes[i].slice());
                p1angle = angleOf(mx,my,ref[i][0],ref[i][1]);
                p2angle = angleOf(mx,my,ref[i][2],ref[i][3]);
                p1radius = ((ref[i][0]-mx)**2+(ref[i][1]-my)**2)**0.5;
                p2radius = ((ref[i][2]-mx)**2+(ref[i][3]-my)**2)**0.5;
                newangle1 = p1angle+a*incang;
                newangle2 = p2angle+a*incang;
                ref[i][0] = mx + p1radius * Math.cos(newangle1);
                ref[i][1] = my + p1radius * Math.sin(newangle1);
                ref[i][2] = mx + p2radius * Math.cos(newangle2);
                ref[i][3] = my + p2radius * Math.sin(newangle2);
            }
            multistrokes.push(ref);
            ref = [];
            for (var i=0;i<strokes.length;i++){
                ref.push(reflection[i].slice());
                p1angle = angleOf(mx,my,ref[i][0],ref[i][1]);
                p2angle = angleOf(mx,my,ref[i][2],ref[i][3]);
                p1radius = ((ref[i][0]-mx)**2+(ref[i][1]-my)**2)**0.5;
                p2radius = ((ref[i][2]-mx)**2+(ref[i][3]-my)**2)**0.5;
                newangle1 = p1angle+a*incang;
                newangle2 = p2angle+a*incang;
                ref[i][0] = mx + p1radius * Math.cos(newangle1);
                ref[i][1] = my + p1radius * Math.sin(newangle1);
                ref[i][2] = mx + p2radius * Math.cos(newangle2);
                ref[i][3] = my + p2radius * Math.sin(newangle2);
            }
            multistrokes.push(ref);
        }
    }
    function draw(add = 1) {

        // ctx.beginPath();
        // ctx.moveTo(prevX, prevY);
        // ctx.lineTo(currX, currY);
        // ctx.strokeStyle = color;
        // ctx.lineWidth = lineWidth;
        // ctx.stroke();
        // ctx.closePath();
        if (color.includes("rgb")){color = rgbStrToHex(color);
                                    } //always turn it into hex
        rgbthis = hexToRgb(color);
       
        if (add == 1){
           strokes.push([prevX,prevY,currX,currY,color,lineWidth,strokecount,rgbthis[0],rgbthis[1],rgbthis[2]]); //        save stroke information as we draw
        }
        if (document.getElementById('reflect').checked){
            multistrokes = [];
            mirrors = parseInt(document.getElementById('mirrors').value);
            reflectthem(mirrors);
        }else{
            multistrokes = [];
        }
        draw1();
        drawCursor();

        ctx.globalAlpha=.5;
        ctx.drawImage(img,0,0,canvas.width,canvas.height);
        ctx.globalAlpha=1.0;
        draw2();
    }
   

    function erase() {
        var m = confirm("Want to clear");
        if (m) {
            strokes = [];
            strokecount = -1;
            ctx.clearRect(0, 0, w, h);
            ctx2.clearRect(0, 0, w, h);
            document.getElementById("canvasimg").style.display = "none";
        }
    }
   
    function save() {
        document.getElementById("canvasimg").style.border = "2px solid";
        var dataURL = canvas.toDataURL();
        document.getElementById("canvasimg").src = dataURL;
        document.getElementById("canvasimg").style.display = "inline";
    }
//     function getMousePos(canvas, evt) {
//   var rect = canvas.getBoundingClientRect();
//   return {
//     x: evt.clientX - rect.left,
//     y: evt.clientY - rect.top
//   };
// }
    function choosexy(res, e) {
        rect = canvas1.getBoundingClientRect();
        if (res == 'down') {
            prevX = currX;
            prevY = currY;
            // currX = e.clientX - canvas1.offsetLeft;
            // currY = e.clientY - canvas1.offsetTop;
            currX = e.clientX - rect.left;
            currY = e.clientY - rect.top;
            if (currX < 640){
                pixel = ctx1.getImageData(currX, currY, 1, 1).data;
                color = "rgb("+pixel[0]+","+pixel[1]+","+pixel[2]+")";
            }else{
                lineWidth = (currX - 640)/120 * (60);
            }
            drawcolors();
        }
    }
   
    function findxy(res, e) {
        rect = canvas.getBoundingClientRect();
        if (res == 'down') {
            prevX = currX;
            prevY = currY;
            // currX = e.clientX - canvas.offsetLeft;
            // currY = e.clientY - canvas.offsetTop;
            currX = e.clientX - rect.left;
            currY = e.clientY - rect.top;
            flag = true;
            dot_flag = true;
            if (dot_flag) {
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.fillRect(currX, currY, 2, 2);
                ctx.closePath();

                ctx2.beginPath();
                ctx2.fillStyle = color;
                ctx2.fillRect(currX, currY, 2, 2);
                ctx2.closePath();
                dot_flag = false;
            }
        }
        if (res == 'up' || res == "out") {
            flag = false;
            strokecount += 1; //increment stroke count
        }
        if (res == 'move') {
            if (flag) {
                prevX = currX;
                prevY = currY;
                // currX = e.clientX - canvas.offsetLeft;
                // currY = e.clientY - canvas.offsetTop;
                currX = e.clientX - rect.left;
                currY = e.clientY - rect.top;
                draw();
            }else{
                // currX = e.clientX - canvas.offsetLeft;
                // currY = e.clientY - canvas.offsetTop;
                currX = e.clientX - rect.left;
                currY = e.clientY - rect.top;
                drawCursor(1);
            }
        }
    }
    function animate(){
        if (document.getElementById('animate').checked){
            draw2();
        }
    }
    setInterval(animate,100);
    function loadimage(){
        image = document.getElementById("img");
        image.onload = function(){
           
            init();
        }
        image.src = document.getElementById('src').value;
    }
    function save(){
        localStorage.setItem("tracer_strokes", JSON.stringify(strokes));
    }
    function load(){
        strokes = JSON.parse(localStorage.getItem("tracer_strokes"));
    }
    draw();
    </script>
    <body onload="init()">
        <canvas id="canvas" width="840" height="80" style="position:absolute;top:0px;left:0px;border:1px solid"></canvas>
        <table><tr><td><img src='square.jpg' id='img' width="2000px" style="position:absolute;top:80px;left:0px;border:2px solid;"><canvas id="can" width="1200" height="1200" style="position:absolute;top:80px;left:0px;border:2px solid;"></canvas></td><td><canvas id="can2" width="1200" height="960" style="position:absolute;top:80px;left:1200px;border:2px solid;"></td>
            <td><canvas id="can3" width="1200" height="960" style="position:absolute;top:80px;left:2400px;border:2px solid;"></td></tr></table><br/>
        <div id='ph' style="position:absolute;top:1100px;left:0%;">
        <input type='submit' value='Clear' onclick='erase()'><br/>
        <input type='checkbox' id='offsetly' value=''>Offsetly Drawn<br/>
        <!-- <input type='checkbox' id='shuffle' value=''>Shuffle Stroke Parts<br/> -->
        <input type="checkbox" id='animate' checked>Continuous Redraws<br/>
        <input type="checkbox" id='varycheckbox' checked>Vary Color Channels by <input type='text' id='varycolorby' value='50' size=3>/255 - <input type="checkbox" id='varywithinstroke'>Vary Within Strokes<br/>
       
        Image location/url:<input type='text' id='src' value='seagull.jpg'><input type='submit' onclick='loadimage()' value='Load Image'><br/>
        <select id="stroketype"><option value="1" selected>Regular Stroke</option>
                               <option value="2">Circles</option>
        </select>
        <input type='checkbox' id='reflect' checked>Reflect <input type='text' id='mirrors' value='6' size=3> Mirrors<br/>
        <input type='checkbox' id='grid' checked>Grid (of Multiples) of <input type='text' id='byValue' value='4' size=3> n by n Value<br/>
        <input type='checkbox' id='progression' checked>Show Progression (when in Grid mode)<br/>
        <input type='submit' value='Redraw Canvas3' onclick='draw3()'><br/>
        <br/>
        <input type='submit' value='Save to Local Storage' onclick='save()'><input type='submit' value='Load from Local Storage' onclick='load()'><br/>

        <div id='debug'></div>
        <hr>
        <div id='donate'>
        The NSI (not so important) stuff: If you find this js/html useful, feel free to use it but if you make money from it (I ask that <br>
        you transfer $1 USD per sale to me through Paypal at oldtran@gmail.com). If you don't use Paypal, then don't worry about it. I understand<br/>
        that there might be fees so maybe save it until you have more than 10 sales then transfer to me once and minus the fee. I would appreciate<br/>
         this and maybe even add features in the future to this existing program.<br/><br/>
        I also ask that you donate $1 per sale to GIMP foundation.<br/><br/>
        I think it's a fair deal, as there is no risk to you for using it for free as much as you please, and only turn around and donate only when you've made sales.<br/>
        </div>
        </div>
</body>
</html>


_________________
TinT


Top
 Post subject: Re: Composed in GIMP
PostPosted: Tue Mar 07, 2023 9:52 am  (#9) 
Offline
Script Coder
User avatar

Joined: May 07, 2014
Posts: 4001
Location: Canada
Just another progression doodle
Image

_________________
TinT


Top
 Post subject: Re: Composed in GIMP
PostPosted: Tue Mar 07, 2023 4:34 pm  (#10) 
Offline
GimpChat Member
User avatar

Joined: Dec 09, 2018
Posts: 656
Hi Tim, I like your doodle :kpix

Thank you for the updates. I tried version 3 and the progression didn't seem to do anything but then I'm not sure what I was looking for and it may be my browser at fault.

Using the mirroring and tiling:

Attachment:
ttp1c.png
ttp1c.png [ 586.1 KiB | Viewed 690 times ]


Attachment:
ttp2c.png
ttp2c.png [ 279.95 KiB | Viewed 690 times ]


Top
 Post subject: Re: Composed in GIMP
PostPosted: Tue Mar 07, 2023 7:58 pm  (#11) 
Offline
Script Coder
User avatar

Joined: May 07, 2014
Posts: 4001
Location: Canada
Yeah with Progression checked you have to have Grid checked as well as it has to use grid to show progression.
If Grid is checked it draws multiples in grid.
But if Progression is checked along with Grid then you'll see progression through the grid.

Oh found a bug(fixed it). (also hosted on https://thelotteryforum.com/tin-man-draw.html)
<html>
<div id="fb-root"></div>
<script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v16.0&appId=2727991274101093&autoLogAppEvents=1" nonce="99M2cCnM"></script>
<h1>Tin Man Draw Page</h1>
<div class="fb-like" data-href="https://thelotteryforum.com/tin-man-draw.html" data-width="" data-layout="" data-action="" data-size="" data-share="true"></div><br/>
<script type="text/javascript">
colors = [["1","Blue Green","#199ebd"],
["2","Black","#232323"],
["3","Blue Violet","#7366bd"],
["4","Violet(Purple)","#926eae"],
["5","Green","#1cac78"],
["6","Blue","#1f75fe"],
["7","Yellow Green","#c5e384"],
["8","White","#ededed"],
["9","Yellow","#fce883"],
["10","Carnation Pink","#ffaacc"],
["11","Yellow Orange","#ffb653"],
["12","Red","#ee204d"],
["13","Brown","#b5674d"],
["14","Orange","#ff7538"],
["15","Red Orange","#ff5349"],
["16","Red Violet","#c0448f"],
["17","Gray","#95918c"],
["18","Cerulean","#1dacd6"],
["19","Indigo","#5d76cb"],
["20","Green Yellow","#f0e891"],
["21","Dandelion","#fddb6d"],
["22","Apricot","#fdd9b5"],
["23","Violet Red","#f75394"],
["24","Scarlet","#fc2847"],
["25","Wisteria","#cda4de"],
["26","Sky Blue","#80daeb"],
["27","Cadet Blue","#b0b7c6"],
["28","Timberwolf","#dbd7d2"],
["29","Melon","#fdbcb4"],
["30","Peach","#ffcfab"],
["31","Tan","#faa76c"],
["32","Chestnut","#bc5d58"],
];
    var varyColorBy = 20; //value to vary each color by out of 255 (plus or minus this value). changed by textbox input later
    var canvas,canvas2, ctx,ctx2, flag,canvas1,ctx1 = false,
        prevX = 0,
        currX = 0,
        prevY = 0,
        currY = 0,
        dot_flag = false;
    var color = colors[1][2];
    var lineWidth = 2;
    base = 70;
    top = 10;   
    function drawcolors(){
        ctx1.clearRect(0,0,canvas1.width,canvas1.height)
        for (var x=0;x<16;x++){
            ctx1.fillStyle = colors[x][2];
            ctx1.fillRect(x*40,0,40,40);
        }   
        for (var x=16;x<32;x++){
            ctx1.fillStyle = colors[x][2];
            ctx1.fillRect((x-16)*40,40,40,40);
        }   
        ctx1.fillStyle = "rgb(0,0,0)";
        ctx1.beginPath();
        ctx1.lineTo(640,70);
        ctx1.lineTo(760,10);
        ctx1.lineTo(760,70);
        ctx1.lineTo(640,70);
        ctx1.closePath();
        ctx1.fill();
       
        //draw brush size
        radius = lineWidth/2.0;
        ctx1.globalAlpha=0.5;
        ctx1.beginPath();
        ctx1.fillStyle = "red";
        ctx1.arc(640+lineWidth*2,70-radius,radius, 0, 2 * Math.PI);
        ctx1.fill();
        ctx1.globalAlpha=1.0;
        ctx1.globalCompositeOperation = "xor";
        ctx1.beginPath();
       
        ctx1.arc(640+lineWidth*2,70-radius,radius, 0, 2 * Math.PI);
        ctx1.stroke();
        ctx1.globalCompositeOperation = "source-over";

        //draw brush size with current color
        ctx1.beginPath();
        ctx1.arc(800,40,radius,0,2*Math.PI);
        ctx1.fillStyle = color;
        ctx1.fill();
    }
    img = 0;
    function init() {
        canvas1 = document.getElementById('canvas');
        ctx1 = canvas1.getContext("2d");
        canvas1.addEventListener("mousedown", function (e) {
            choosexy('down', e)
        }, false);

        canvas = document.getElementById('can');
        canvas2 = document.getElementById('can2');
        canvas3 = document.getElementById('can3');

        ctx = canvas.getContext("2d");
        ctx2 = canvas2.getContext("2d");
        ctx3 = canvas3.getContext("2d");
        img = document.getElementById("img");
        canvas.width = img.width;
        canvas.height = img.height;
        canvas2.width = canvas.width;
        canvas2.height = canvas.height;
        canvas3.width = canvas.width;
        canvas3.height = canvas.height;
        w = canvas.width;
        h = canvas.height;
        ph = document.getElementById('ph');
        ph.style.top = parseInt(canvas.height)+100+"px";
        canvas2.style.left = parseInt(canvas.width)+10+"px";
        canvas3.style.left = (parseInt(canvas.width)+10)*2 + "px";

        ctx.lineCap = "round";
        ctx2.lineCap = "round";
        canvas.addEventListener("mousemove", function (e) {
            findxy('move', e)
        }, false);
        canvas.addEventListener("mousedown", function (e) {
            findxy('down', e)
        }, false);
        canvas.addEventListener("mouseup", function (e) {
            findxy('up', e)
        }, false);
        canvas.addEventListener("mouseout", function (e) {
            findxy('out', e)
        }, false);
        drawcolors();
    }
    strokes = [];
    multistrokes = [];
    strokecount = -1;
    function shuffle_(array) {
        let currentIndex = array.length,  randomIndex;
    // While there remain elements to shuffle.
      while (currentIndex != 0) {

    // Pick a remaining element.
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;

    // And swap it with the current element.
        [array[currentIndex], array[randomIndex]] = [   
        array[randomIndex], array[currentIndex]];
    }
    return array;
    }
    function componentToHex(c) {
  var hex = c.toString(16);
  return hex.length == 1 ? "0" + hex : hex;
}

function rgbToHex(r, g, b) {
  return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
function rgbStrToHex(rgbstring){
    rgb = rgbstring;
    //rgb = "rgb(0,128,255)"
    values = rgb.slice(4,-1).split(',');
return rgbToHex(parseInt(values[0]),parseInt(values[1]),parseInt(values[2]));
}
const hexToRgb = hex =>
  hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i
             ,(m, r, g, b) => '#' + r + r + g + g + b + b)
    .substring(1).match(/.{2}/g)
    .map(x => parseInt(x, 16));
     function width_(array){
       halfsize = array.length/2.0;
       currentlw = array[0][5];
       c = array[0][4];
       currentc = hexToRgb(c);
       r = parseInt(currentc[0]);
       g = parseInt(currentc[1]);
       b = parseInt(currentc[2]);
       if (document.getElementById('varycheckbox').checked){ //if it's check we vary random within varycolorby range
           varColorBy = parseInt(document.getElementById('varycolorby').value);
           r = Math.min(255,Math.max(0,r+Math.random()*varColorBy*2-varColorBy));
           g = Math.min(255,Math.max(0,g+Math.random()*varColorBy*2-varColorBy));
           b = Math.min(255,Math.max(0,b+Math.random()*varColorBy*2-varColorBy));
       }
       for (var i=0;i<array.length;i++){
             angle = (90-Math.abs((halfsize)-i)/(halfsize)*90.0)/360.0*2.0*3.1415;
             thislw = currentlw * 0.1 + Math.sin(angle)*currentlw*1.0;
             array[i][5] = thislw;
         
                currentc = hexToRgb(c);
                //document.getElementById('debug').innerHTML += currentc + ",";
           
            if (document.getElementById('varywithinstroke').checked){ //if it's check we vary random within varycolorby range
                r = parseInt(currentc[0]);
                g = parseInt(currentc[1]);
                b = parseInt(currentc[2]);
                varColorBy = parseInt(document.getElementById('varycolorby').value);
                r = Math.min(255,Math.max(0,r+Math.random()*varColorBy*2-varColorBy));
                g = Math.min(255,Math.max(0,g+Math.random()*varColorBy*2-varColorBy));
                b = Math.min(255,Math.max(0,b+Math.random()*varColorBy*2-varColorBy));
            }
           
            maxbrightvalue = Math.max(r,g,b);
            ubound = (Math.min(maxbrightvalue*1.3,255.0))/maxbrightvalue;
            lbound = 0.8;
            fraction = ubound - Math.sin(angle)*(ubound-lbound);
             thisr = parseInt(r*fraction);
             thisg = parseInt(g*fraction);
             thisb = parseInt(b*fraction);
             
             array[i][7] = thisr;
             array[i][8] = thisg;
             array[i][9] = thisb;
       }
       
       return array;
    }

    function angleOf(cx, cy, ex, ey) {//returns angle in degrees
        var dy = ey - cy;
        var dx = ex - cx;
        var theta = Math.atan2(dy, dx); // range (-PI, PI]
        //theta *= 180 / Math.PI; // rads to degs, range (-180, 180]
        //if (theta < 0) theta = 360 + theta; // range [0, 360)
        return theta;
    }
   
    function strokeShuffle(){
        strokes2 = [];
        lsc = -1;
        thisstrokes = [];
        for (var i=0;i<strokes.length;i++){
            sc = strokes[i][6];
            if (sc!=lsc){
                if (thisstrokes.length > 0){
                    thisstrokes = shuffle_(thisstrokes.slice());
                    for (var j=0;j<thisstrokes.length;j++){
                        strokes2.push(thisstrokes[j].slice());
                    }
                }
                thisstrokes = [];
                lsc = sc;
            }
            thisstrokes.push(strokes[i].slice());
        }
        if (thisstrokes.length > 0){
            thisstrokes = shuffle_(thisstrokes.slice());
            for (var j=0;j<thisstrokes.length;j++){
                strokes2.push(thisstrokes[j].slice());
                }
        }
        return strokes2;
    }
    function strokeWidth(strokes){
        strokes2 = [];
        lsc = -1;
        thisstrokes = [];
        for (var i=0;i<strokes.length;i++){
            sc = strokes[i][6];
            if (sc!=lsc || i == 0){
                if (thisstrokes.length > 0){
                    thisstrokes = width_(thisstrokes.slice());
                    for (var j=0;j<thisstrokes.length;j++){
                        strokes2.push(thisstrokes[j].slice());
                    }
                }
                thisstrokes = [];
                lsc = sc;
            }
            thisstrokes.push(strokes[i].slice());
        }
        if (thisstrokes.length > 0){
            thisstrokes = width_(thisstrokes.slice());
            for (var j=0;j<thisstrokes.length;j++){
                strokes2.push(thisstrokes[j].slice());
                }
        }
        return strokes2;
    }
    function draw2(){
        ctx2.clearRect(0, 0, w, h);
        for (var s=-1;s<multistrokes.length;s++){
            lc = -1;
            llw = -1;
            lsc = -1;
            //strokes2 = strokeWidth(strokes.slice());
            if (s==-1){
                strokes2 = strokeWidth(strokes.slice());
            }else{
                strokes2 = strokeWidth(multistrokes[s].slice());
            }

            for (var i=0;i<strokes2.length;i++){
                    dx1 = strokes2[i][0];
                    dy1 = strokes2[i][1];
                    dx2 = strokes2[i][2];
                    dy2 = strokes2[i][3];
                    dc = strokes2[i][4];
                    lw = strokes2[i][5];
                    sc = strokes2[i][6];
                    r = strokes2[i][7];
                    g = strokes2[i][8];
                    b = strokes2[i][9];
                if (document.getElementById('offsetly').checked){
                    ox = (dx2-dx1) * (Math.random()*0.4+0.8)/2.0;
                    oy = (dy2-dy1) * (Math.random()*0.4+0.8)/2.0;
                    cx = (dx2+dx1)/2.0;
                    cy = (dy2+dy1)/2.0;
                    dx1 = cx - ox;
                    dy1 = cy - oy;
                    dx2 = cx + ox;
                    dy2 = cy + oy;
                }
                //if ((lc != dc) || (llw != lw) ||) { //if it's the first stroke we set lx and ly to start there
                if (lsc != sc) { //if different stroke count
                   lx = dx1;
                   ly = dy1;
                   lc = dc;
                   llw = lw;
                   lsc = sc;
                } 
                if (Math.random()>=0.0) {
                    if (document.getElementById('offsetly').checked){
                        nx = dx2-dx1;
                        ny = dy2-dy1;
                        dx1 = lx;
                        dy1 = ly;
                        dx2 = lx+nx;
                        dy2 = ly+ny;
                    }
                    if (document.getElementById('stroketype').value == "1"){ //regular stroke
                        ctx2.beginPath();
                        ctx2.moveTo(dx1,dy1);
                        ctx2.lineTo(dx2,dy2);
                        //ctx2.strokeStyle = dc;
                        ctx2.strokeStyle = "rgb("+r+","+g+","+b+")";
                        ctx2.lineWidth = lw;
                        ctx2.stroke();
                        ctx2.closePath();
                    }else if (document.getElementById('stroketype').value == "2"){ //circles
                        ctx2.beginPath();
                        cx = (dx1+dx2)/2;
                        cy = (dy1+dy1)/2;
                        //ctx2.strokeStyle = dc;
                        ctx2.strokeStyle = "rgb("+r+","+g+","+b+")";
                        //ctx2.lineWidth = lw;
                        ctx2.lineWidth = Math.max(1.0,lw/10.0);
                        ctx2.arc(cx,cy,lw/2.0,0,Math.PI*2);
                        ctx2.stroke();
                        ctx2.closePath();
                    }
                    lx = dx2;
                    ly = dy2;
                }     
            }
        }
    }
    function draw1(){
        ctx.clearRect(0, 0, w, h);
        for (var i=0;i<strokes.length;i++){
                dx1 = strokes[i][0];
                dy1 = strokes[i][1];
                dx2 = strokes[i][2];
                dy2 = strokes[i][3];
                dc = strokes[i][4];
                lw = strokes[i][5];
                sc = strokes[i][6];
                 ctx.beginPath();
                ctx.moveTo(dx1,dy1);
                ctx.lineTo(dx2,dy2);
                ctx.strokeStyle = dc;
                ctx.lineWidth = lw;
                ctx.stroke();
                ctx.closePath();
        }
        if (document.getElementById('reflect').checked){
            for (var j=0;j<multistrokes.length;j++){
                stroke = multistrokes[j];
                for (var i=0;i<stroke.length;i++){
                    dx1 = stroke[i][0];
                    dy1 = stroke[i][1];
                    dx2 = stroke[i][2];
                    dy2 = stroke[i][3];
                    dc = stroke[i][4];
                    lw = stroke[i][5];
                    sc = stroke[i][6];
                     ctx.beginPath();
                    ctx.moveTo(dx1,dy1);
                    ctx.lineTo(dx2,dy2);
                    ctx.strokeStyle = dc;
                    ctx.lineWidth = lw;
                    ctx.stroke();
                    ctx.closePath();
                }             
            }
        }
        // ctx.beginPath();
        // ctx.moveTo(prevX, prevY);
        // ctx.lineTo(currX, currY);
        // ctx.strokeStyle = color;
        // ctx.lineWidth = lineWidth;
        // ctx.stroke();
        // ctx.closePath();
    }
    function draw3(){
        ctx3.globalAlpha = 1.0;
        ctx3.clearRect(0,0,canvas3.width,canvas3.height);
        //ctx3.fillStyle= 'white';
        //ctx3.fillRect(0,0,canvas3.width,canvas3.height);
        progression = 0;
        by = parseInt(document.getElementById("byValue").value);
        if (document.getElementById("grid").checked && document.getElementById("progression").checked){
           
            progressions = by * by;
            progression = 1;
            p = []; //progressions
            savedstrokes = strokes.slice();
            for (var i=1;i<=progressions;i++){
                p.push(strokes.slice(0,Math.round(strokes.length/progressions*i)));
            }
        }
               
        for (var i=1;i<=8;i++){
            if (document.getElementById("grid").checked){
                size = canvas.width/by;
                n = 0;
                for (var y=0;y<by;y++){
                    for (var x=0;x<by;x++){
                        if (progression==1){
                            strokes = p[n].slice();
                            draw(0); //to calculate multi strokes
                        }
                        n+=1;
                        draw2();
                        ctx3.globalAlpha = 1.0/(i+1);
                        ctx3.drawImage(canvas2,x*size,y*size,size,size);
                    }
                }
            }else{
                draw2();
                ctx3.globalAlpha = 1.0/(i+1);
                ctx3.drawImage(canvas2,0,0);
            }
        }
        if (progression==1){
            strokes = savedstrokes.slice();
        }
    }
    function drawCursor(clear = 0){
        if (clear == 1){
            ctx.clearRect(0,0,canvas.width,canvas.height);
            //redisplay them all before drawing cursor
        //ctx.globalAlpha=1.0;
        //ctx.drawImage(img,0,0,canvas.width,canvas.height);
        draw1();
        ctx.globalAlpha=.5;
        ctx.drawImage(img,0,0,canvas.width,canvas.height);
        ctx.globalAlpha=1.0;
        }
       



        ctx.beginPath();
        ctx.arc(currX,currY,lineWidth/2.0,0,Math.PI*2.0);
        saveLineWith = ctx.lineWidth;
        ctx.lineWidth = 1;
        savestrokeStyle = ctx.strokeStyle;
        ctx.strokeStyle = 'red';
        ctx.globalCompositeOperation = "xor";
        ctx.stroke();
        ctx.globalCompositeOperation = "source-over";
        ctx.strokeStyle = savestrokeStyle;
        ctx.lineWidth = saveLineWith;
    }
    mirrors = 6;
    function reflectthem(mirrors){
        mirrors = parseInt(mirrors);
        reflection = [];
        mx = canvas.width/2.0;
        my = canvas.height/2.0;
        for (var i=0;i<strokes.length;i++){
            reflection.push(strokes[i].slice());
            reflection[i][0] = mx - (reflection[i][0] - mx);
            reflection[i][2] = mx - (reflection[i][2] - mx);
        }
        multistrokes.push(reflection);
        incang = 360.0/mirrors/360.0*2*Math.PI;
        for (var a=1;a<mirrors;a++){
            ref = [];
            for (var i=0;i<strokes.length;i++){
                ref.push(strokes[i].slice());
                p1angle = angleOf(mx,my,ref[i][0],ref[i][1]);
                p2angle = angleOf(mx,my,ref[i][2],ref[i][3]);
                p1radius = ((ref[i][0]-mx)**2+(ref[i][1]-my)**2)**0.5;
                p2radius = ((ref[i][2]-mx)**2+(ref[i][3]-my)**2)**0.5;
                newangle1 = p1angle+a*incang;
                newangle2 = p2angle+a*incang;
                ref[i][0] = mx + p1radius * Math.cos(newangle1);
                ref[i][1] = my + p1radius * Math.sin(newangle1);
                ref[i][2] = mx + p2radius * Math.cos(newangle2);
                ref[i][3] = my + p2radius * Math.sin(newangle2);
            }
            multistrokes.push(ref);
            ref = [];
            for (var i=0;i<strokes.length;i++){
                ref.push(reflection[i].slice());
                p1angle = angleOf(mx,my,ref[i][0],ref[i][1]);
                p2angle = angleOf(mx,my,ref[i][2],ref[i][3]);
                p1radius = ((ref[i][0]-mx)**2+(ref[i][1]-my)**2)**0.5;
                p2radius = ((ref[i][2]-mx)**2+(ref[i][3]-my)**2)**0.5;
                newangle1 = p1angle+a*incang;
                newangle2 = p2angle+a*incang;
                ref[i][0] = mx + p1radius * Math.cos(newangle1);
                ref[i][1] = my + p1radius * Math.sin(newangle1);
                ref[i][2] = mx + p2radius * Math.cos(newangle2);
                ref[i][3] = my + p2radius * Math.sin(newangle2);
            }
            multistrokes.push(ref);
        }
    }
    function draw(add = 1) {

        // ctx.beginPath();
        // ctx.moveTo(prevX, prevY);
        // ctx.lineTo(currX, currY);
        // ctx.strokeStyle = color;
        // ctx.lineWidth = lineWidth;
        // ctx.stroke();
        // ctx.closePath();
        if (color.includes("rgb")){color = rgbStrToHex(color);
                                    } //always turn it into hex
        rgbthis = hexToRgb(color);
       
        if (add == 1){
           strokes.push([prevX,prevY,currX,currY,color,lineWidth,strokecount,rgbthis[0],rgbthis[1],rgbthis[2]]); //        save stroke information as we draw
        }
        if (document.getElementById('reflect').checked){
            multistrokes = [];
            mirrors = parseInt(document.getElementById('mirrors').value);
            reflectthem(mirrors);
        }else{
            multistrokes = [];
        }
        draw1();
        drawCursor();

        ctx.globalAlpha=.5;
        ctx.drawImage(img,0,0,canvas.width,canvas.height);
        ctx.globalAlpha=1.0;
        draw2();
    }
   

    function erase() {
        var m = confirm("Want to clear");
        if (m) {
            strokes = [];
            strokecount = -1;
            ctx.clearRect(0, 0, w, h);
            ctx2.clearRect(0, 0, w, h);
            document.getElementById("canvasimg").style.display = "none";
        }
    }
   
    function save() {
        document.getElementById("canvasimg").style.border = "2px solid";
        var dataURL = canvas.toDataURL();
        document.getElementById("canvasimg").src = dataURL;
        document.getElementById("canvasimg").style.display = "inline";
    }
//     function getMousePos(canvas, evt) {
//   var rect = canvas.getBoundingClientRect();
//   return {
//     x: evt.clientX - rect.left,
//     y: evt.clientY - rect.top
//   };
// }
    function choosexy(res, e) {
        rect = canvas1.getBoundingClientRect();
        if (res == 'down') {
            prevX = currX;
            prevY = currY;
            // currX = e.clientX - canvas1.offsetLeft;
            // currY = e.clientY - canvas1.offsetTop;
            currX = e.clientX - rect.left;
            currY = e.clientY - rect.top;
            if (currX < 640){
                pixel = ctx1.getImageData(currX, currY, 1, 1).data;
                color = "rgb("+pixel[0]+","+pixel[1]+","+pixel[2]+")";
            }else{
                lineWidth = (currX - 640)/120 * (60);
            }
            drawcolors();
        }
    }
   
    function findxy(res, e) {
        rect = canvas.getBoundingClientRect();
        if (res == 'down') {
            prevX = currX;
            prevY = currY;
            // currX = e.clientX - canvas.offsetLeft;
            // currY = e.clientY - canvas.offsetTop;
            currX = e.clientX - rect.left;
            currY = e.clientY - rect.top;
            flag = true;
            dot_flag = true;
            if (dot_flag) {
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.fillRect(currX, currY, 2, 2);
                ctx.closePath();

                ctx2.beginPath();
                ctx2.fillStyle = color;
                ctx2.fillRect(currX, currY, 2, 2);
                ctx2.closePath();
                dot_flag = false;
            }
        }
        if (res == 'up' || res == "out") {
            flag = false;
            strokecount += 1; //increment stroke count
        }
        if (res == 'move') {
            if (flag) {
                prevX = currX;
                prevY = currY;
                // currX = e.clientX - canvas.offsetLeft;
                // currY = e.clientY - canvas.offsetTop;
                currX = e.clientX - rect.left;
                currY = e.clientY - rect.top;
                draw();
            }else{
                // currX = e.clientX - canvas.offsetLeft;
                // currY = e.clientY - canvas.offsetTop;
                currX = e.clientX - rect.left;
                currY = e.clientY - rect.top;
                drawCursor(1);
            }
        }
    }
    function animate(){
        if (document.getElementById('animate').checked){
            draw2();
        }
    }
    setInterval(animate,100);
    function loadimage(){
        image = document.getElementById("img");
        image.onload = function(){
           
            init();
        }
        image.src = document.getElementById('src').value;
    }
    function save(){
        localStorage.setItem("tracer_strokes", JSON.stringify(strokes));
    }
    function load(){
        strokes = JSON.parse(localStorage.getItem("tracer_strokes"));
    }
    draw();
    </script>
    <body onload="init()">
        <canvas id="canvas" width="840" height="80" style="position:absolute;top:100px;left:0px;border:1px solid"></canvas>
        <table><tr><td><img src='square.jpg' id='img' width="2000px" style="position:absolute;top:180px;left:0px;border:2px solid;"><canvas id="can" width="1200" height="1200" style="position:absolute;top:180px;left:0px;border:2px solid;"></canvas></td><td><canvas id="can2" width="1200" height="960" style="position:absolute;top:180px;left:1200px;border:2px solid;"></td>
            <td><canvas id="can3" width="1200" height="960" style="position:absolute;top:180px;left:2400px;border:2px solid;"></td></tr></table><br/>
        <div id='ph' style="position:absolute;top:2300px;left:0%;">
        <input type='submit' value='Clear' onclick='erase()'><br/>
        <input type='checkbox' id='offsetly' value=''>Offsetly Drawn<br/>
        <!-- <input type='checkbox' id='shuffle' value=''>Shuffle Stroke Parts<br/> -->
        <input type="checkbox" id='animate' checked>Continuous Redraws<br/>
        <input type="checkbox" id='varycheckbox' checked>Vary Color Channels by <input type='text' id='varycolorby' value='50' size=3>/255 - <input type="checkbox" id='varywithinstroke'>Vary Within Strokes<br/>
       
        Image location/url:<input type='text' id='src' value='seagull.jpg'><input type='submit' onclick='loadimage()' value='Load Image'><br/>
        <select id="stroketype"><option value="1" selected>Regular Stroke</option>
                               <option value="2">Circles</option>
        </select>
        <input type='checkbox' id='reflect' checked>Reflect <input type='text' id='mirrors' value='6' size=3> Mirrors<br/>
        <input type='checkbox' id='grid' checked>Grid (of Multiples) of <input type='text' id='byValue' value='4' size=3> n by n Value<br/>
        <input type='checkbox' id='progression' checked>Show Progression (when in Grid mode)<br/>
        <input type='submit' value='Redraw Canvas3' onclick='draw3()'><br/>
        <br/>
        <input type='submit' value='Save to Local Storage' onclick='save()'><input type='submit' value='Load from Local Storage' onclick='load()'><br/>

        <div id='debug'></div>
        <hr>
        <div id='donate'>
        The NSI (not so important) stuff: If you find this js/html useful, feel free to use it but if you make money from it (I ask that <br>
        you transfer $1 USD per sale to me through Paypal at oldtran@gmail.com). If you don't use Paypal, then don't worry about it. I understand<br/>
        that there might be fees so maybe save it until you have more than 10 sales then transfer to me once and minus the fee. I would appreciate<br/>
         this and maybe even add features in the future to this existing program.<br/><br/>
        I also ask that you donate $1 per sale to GIMP foundation.<br/><br/>
        I think it's a fair deal, as there is no risk to you for using it for free as much as you please, and only turn around and donate only when you've made sales.<br/>
        </div>
        </div>
</body>
</html>

www.youtube.com Video from : www.youtube.com

_________________
TinT


Top
 Post subject: Re: Composed in GIMP
PostPosted: Wed Mar 08, 2023 8:14 pm  (#12) 
Offline
GimpChat Member
User avatar

Joined: Dec 09, 2018
Posts: 656
I'm not on facebook so can't do the like, but I do like it :tyspin


Top
 Post subject: Re: Composed in GIMP
PostPosted: Wed Mar 08, 2023 8:33 pm  (#13) 
Offline
GimpChat Member
User avatar

Joined: Sep 24, 2010
Posts: 12531
But it requires you to actually paint (and I'm a filter guy). lol

Did toy with it some, Tran and can see it being useful for those willing to work with it. :)

_________________
Lyle

Psalm 109:8

Image


Top
 Post subject: Re: Composed in GIMP
PostPosted: Thu Mar 09, 2023 6:32 am  (#14) 
Offline
Script Coder
User avatar

Joined: May 07, 2014
Posts: 4001
Location: Canada
teapot wrote:
I'm not on facebook so can't do the like, but I do like it :tyspin

I just changed it from facebook like to a third party like that doesn't require any account to like hehe

_________________
TinT


Top
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC - 5 hours [ DST ]


   Similar Topics   Replies 
No new posts Attachment(s) Gimp tries to save a composed image to windows system32 by default

1



* Login  



Powered by phpBB3 © phpBB Group