├── README.md ├── css ├── normalize.css └── style.css ├── img └── 1.png ├── js ├── 1.js ├── 2.js └── 3.js └── tests ├── 1.html ├── 2.html └── 3.html /README.md: -------------------------------------------------------------------------------- 1 | ## Image Manipulator 2 | 3 | ![Demo](https://i.imgur.com/UOBZ2rx.png) 4 | 5 | Originally inspired by [The Gentlewoman](http://thegentlewoman.co.uk/library/adele) and created to help with automation of image editing process, this tool focuses on a spectrum of RGB and replaces it with a newly desired RGBA. 6 | 7 | The first function converts a `.png/.jpg` to [base64](http://kangax.github.io/jstests/toDataUrl_mime_type_test/), and the second function uses `getImageData` and `putImageData` to adjust the RGB to RGBA. 8 | 9 | The reason this tool is helpful is because `mix-blend-mode` and `background-filter` suck if your image sucks. 10 | 11 | - [Live Demo 1](https://codepen.io/danielhaim1/pen/oxwbBR) 12 | - [Live Demo 2](https://codepen.io/danielhaim1/pen/BKZjwQ?editors=1010) 13 | 14 | ### Usage 15 | ```js 16 | // ! define new RGBA 17 | newcolor = { 18 | r: 255, 19 | g: 255, 20 | b: 255, 21 | a: 0 // 0-255 22 | }; 23 | 24 | // ! ISO anything < 190,190,190 25 | if (r >= 199 && g >= 199 && b >= 199) { 26 | pix[i] = newcolor.r; 27 | pix[i + 1] = newcolor.g; 28 | pix[i + 2] = newcolor.b; 29 | pix[i + 3] = newcolor.a; 30 | } 31 | ``` 32 | 33 | ### Tests 34 | 35 | There are 3 recipes available in `test/` dir. Everything's vanilla, I'm just sharing the love. 36 | 37 | ### Note 38 | 39 | If you receive `Image from origin 'file://' has been blocked from loading by Cross-Origin Resource Sharing policy: Invalid response. Origin 'null' is therefore not allowed access.` that's because Canvas requires a web server. 40 | 41 | ### Resources 42 | 43 | - [Pixel manipulation with canvas](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas) 44 | - [Further info on pixel manipulation with canvas](http://beej.us/blog/data/html5s-canvas-2-pixel/) 45 | 46 | 47 | #### Issues? 48 | Tweet me [@danielhaim](https://twitter.com/danielhaim) 49 | -------------------------------------------------------------------------------- /css/normalize.css: -------------------------------------------------------------------------------- 1 | article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}audio,canvas,video{display:inline-block;}audio:not([controls]){display:none;height:0;}[hidden]{display:none;}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;}body{margin:0;}a:focus{outline:thin dotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em 0;}abbr[title]{border-bottom:1px dotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C" "\201D" "\2018" "\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}figure{margin:0;}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em;}legend{border:0;padding:0;}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;}button,input{line-height:normal;}button,select{text-transform:none;}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}button[disabled],html input[disabled]{cursor:default;}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}textarea{overflow:auto;vertical-align:top;}table{border-collapse:collapse;border-spacing:0;} -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | -webkit-box-sizing: border-box; 5 | box-sizing: border-box; 6 | } 7 | 8 | html{ 9 | font-size: 16px; 10 | } 11 | 12 | body{ 13 | background-color: #fff; 14 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAJUlEQVQYV2O8du3afwY0oKWlxYguxjgUFKI7GsTH5m4M3w1ChQAoMCWQH4AXRAAAAABJRU5ErkJggg=='); 15 | background-repeat: repeat; 16 | background-size: auto; 17 | font-family: sans-serif; 18 | 19 | font-family: system-ui; 20 | font-weight: normal; 21 | } 22 | 23 | h3.original{color:blue;} 24 | h3.modified{color:red;} 25 | h3{font-size: 1.4rem;} 26 | 27 | .example-container{ 28 | display: flex; 29 | justify-content: space-between; 30 | align-items: center; 31 | 32 | max-width: 800px; 33 | min-width: 800px; 34 | margin: 0 auto; 35 | } 36 | 37 | #canvas{ 38 | width: 294px; 39 | height: 294px; 40 | } 41 | 42 | header{ 43 | display: inline-block; 44 | background-color: rgba(0,0,0,0.7); 45 | color: #FFF; 46 | margin: 10px 0 0 10px; 47 | padding: 1rem; 48 | max-width: 200px; 49 | line-height: 1.5; 50 | } 51 | 52 | header h4, 53 | header p{ 54 | font-size: 1rem; 55 | margin: 0; 56 | padding: 0; 57 | } 58 | 59 | header h4{ 60 | margin: 0 0 1em; 61 | } -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielhaim1/img-manipulator/9fb42819baf0dddbab9bbf70db73329c3ff6c0e0/img/1.png -------------------------------------------------------------------------------- /js/1.js: -------------------------------------------------------------------------------- 1 | function toDataURL(src, callback, outputFormat) { 2 | var img = new Image(); 3 | img.crossOrigin = 'Anonymous'; 4 | 5 | img.onload = function() { 6 | var canvas = document.createElement('CANVAS'); 7 | var ctx = canvas.getContext('2d'); 8 | var dataURL; 9 | canvas.height = this.naturalHeight; 10 | canvas.width = this.naturalWidth; 11 | ctx.drawImage(this, 0, 0); 12 | dataURL = canvas.toDataURL(outputFormat); 13 | callback(dataURL); 14 | 15 | 16 | // ----------------------------------- 17 | // Modified Image Canvas 18 | 19 | var modifiedCanvas = document.getElementById("canvas"), 20 | ctx = modifiedCanvas.getContext("2d"); 21 | 22 | // define canvas height/width 23 | modifiedCanvas.height = 294; 24 | modifiedCanvas.width = 294; 25 | ctx.drawImage(img, 0, 0); 26 | 27 | var imgd = ctx.getImageData(0, 0, 294, 294), 28 | pix = imgd.data; 29 | 30 | 31 | // *********************************** 32 | // ----- START HERE ------------------ 33 | 34 | newColor = { 35 | // change these to replace the RGBA 36 | r: 255, // RED 1-255 37 | g: 255, // GREEN 1-255 38 | b: 255, // BLUE 1-255 39 | a: 0 // ALPHA 1-255 40 | }; 41 | 42 | for (var i = 0, n = pix.length; i < n; i += 4) { 43 | 44 | var 45 | r = pix[i], 46 | g = pix[i + 1], 47 | b = pix[i + 2]; 48 | a = pix[i + 3]; 49 | 50 | // if pixels are greater than rgba(200,200,200) "white"; 51 | // Combine RGB, divide by 5 and replace with A ("rgbA") 52 | 53 | if (r <= 190 && g <= 190 && b <= 190) { 54 | var mycolor = (r + g + b) / 3; 55 | pix[i + 3] = mycolor; 56 | } 57 | } 58 | 59 | // ----- STOP HERE ------------------- 60 | // *********************************** 61 | 62 | ctx.putImageData(imgd, 0, 0); 63 | }; 64 | img.src = src; 65 | } 66 | toDataURL('../img/1.png', function(dataUrl) { 67 | var image = document.getElementById("testImage"); 68 | image.src = dataUrl; 69 | }); -------------------------------------------------------------------------------- /js/2.js: -------------------------------------------------------------------------------- 1 | function toDataURL(src, callback, outputFormat) { 2 | var img = new Image(); 3 | img.crossOrigin = 'Anonymous'; 4 | 5 | img.onload = function() { 6 | var canvas = document.createElement('CANVAS'); 7 | var ctx = canvas.getContext('2d'); 8 | var dataURL; 9 | canvas.height = this.naturalHeight; 10 | canvas.width = this.naturalWidth; 11 | ctx.drawImage(this, 0, 0); 12 | dataURL = canvas.toDataURL(outputFormat); 13 | callback(dataURL); 14 | 15 | 16 | // ----------------------------------- 17 | // Modified Image Canvas 18 | 19 | var modifiedCanvas = document.getElementById("canvas"), 20 | ctx = modifiedCanvas.getContext("2d"); 21 | 22 | // define canvas height/width 23 | modifiedCanvas.height = 294; 24 | modifiedCanvas.width = 294; 25 | ctx.drawImage(img, 0, 0); 26 | 27 | var imgd = ctx.getImageData(0, 0, 294, 294), 28 | pix = imgd.data; 29 | 30 | // *********************************** 31 | // ----- START HERE ------------------ 32 | 33 | var0 = { 34 | r: 255, // RED 1-255 35 | g: 255, // GREEN 1-255 36 | b: 255, // BLUE 1-255 37 | a: 0 // ALPHA 1-255 38 | }; 39 | 40 | var1 = { 41 | r: 41, // RED 1-255 42 | g: 41, // GREEN 1-255 43 | b: 41, // BLUE 1-255 44 | a: 255 // ALPHA 1-255 45 | }; 46 | 47 | var2 = { 48 | r: 50, // RED 1-255 49 | g: 46, // GREEN 1-255 50 | b: 49, // BLUE 1-255 51 | a: 255 // ALPHA 1-255 52 | }; 53 | 54 | var3 = { 55 | r: 20, // RED 1-255 56 | g: 74, // GREEN 1-255 57 | b: 100, // BLUE 1-255 58 | a: 50 // ALPHA 1-255 59 | }; 60 | 61 | for (var i = 0, n = pix.length; i < n; i += 4) { 62 | var 63 | r = pix[i], 64 | g = pix[i + 1], 65 | b = pix[i + 2]; 66 | a = pix[i + 3]; 67 | 68 | // if pixels are greater than rgba(200,200,200) "white"; 69 | if (r >= 199 && g >= 199 && b >= 199) { 70 | pix[i] = var0.r; 71 | pix[i + 1] = var0.g; 72 | pix[i + 2] = var0.b; 73 | pix[i + 3] = var0.a; 74 | } 75 | 76 | if (r <= 255 && g <= 255 && b >= 200) { 77 | pix[i] = var3.r; 78 | pix[i + 1] = var3.g; 79 | pix[i + 2] = var3.b; 80 | pix[i + 3] = var3.a; 81 | } 82 | 83 | if (r <= 35 && g <= 35 && b <= 35) { 84 | pix[i] = var1.r; 85 | pix[i + 1] = var1.g; 86 | pix[i + 2] = var1.b; 87 | pix[i + 3] = var1.a; 88 | } 89 | 90 | if (r <= 15 && g <= 15 && b <= 15) { 91 | pix[i] = var2.r; 92 | pix[i + 1] = var2.g; 93 | pix[i + 2] = var2.b; 94 | pix[i + 3] = var2.a; 95 | } 96 | } 97 | 98 | // ----- STOP HERE ------------------- 99 | // *********************************** 100 | 101 | ctx.putImageData(imgd, 0, 0); 102 | }; 103 | img.src = src; 104 | } 105 | toDataURL('../img/1.png', function(dataUrl) { 106 | var image = document.getElementById("testImage"); 107 | image.src = dataUrl; 108 | }); -------------------------------------------------------------------------------- /js/3.js: -------------------------------------------------------------------------------- 1 | function toDataURL(src, callback, outputFormat) { 2 | var img = new Image(); 3 | img.crossOrigin = 'Anonymous'; 4 | 5 | img.onload = function() { 6 | var canvas = document.createElement('CANVAS'); 7 | var ctx = canvas.getContext('2d'); 8 | var dataURL; 9 | canvas.height = this.naturalHeight; 10 | canvas.width = this.naturalWidth; 11 | ctx.drawImage(this, 0, 0); 12 | dataURL = canvas.toDataURL(outputFormat); 13 | callback(dataURL); 14 | 15 | 16 | // ----------------------------------- 17 | // Modified Image Canvas 18 | 19 | var modifiedCanvas = document.getElementById("canvas"), 20 | ctx = modifiedCanvas.getContext("2d"); 21 | 22 | // define canvas height/width 23 | modifiedCanvas.height = 294; 24 | modifiedCanvas.width = 294; 25 | ctx.drawImage(img, 0, 0); 26 | 27 | var imgd = ctx.getImageData(0, 0, 294, 294), 28 | pix = imgd.data; 29 | 30 | // *********************************** 31 | // ----- START HERE ------------------ 32 | 33 | colorWhite = { 34 | r: 255, // RED 1-255 35 | g: 2, // GREEN 1-255 36 | b: 0, // BLUE 1-255 37 | a: 150 // ALPHA 1-255 38 | }; 39 | 40 | for (var i = 0, n = pix.length; i < n; i += 4) { 41 | var 42 | r = pix[i], 43 | g = pix[i + 1], 44 | b = pix[i + 2]; 45 | a = pix[i + 3]; 46 | 47 | // if pixels are greater than rgba(200,200,200) "white"; 48 | if (r >= 199 && g >= 199 && b >= 199) { 49 | pix[i] = colorWhite.r; 50 | pix[i + 1] = colorWhite.g; 51 | pix[i + 2] = colorWhite.b; 52 | pix[i + 3] = colorWhite.a; 53 | } 54 | } 55 | 56 | // ----- STOP HERE ------------------- 57 | // *********************************** 58 | 59 | ctx.putImageData(imgd, 0, 0); 60 | }; 61 | img.src = src; 62 | } 63 | toDataURL('../img/1.png', function(dataUrl) { 64 | var image = document.getElementById("testImage"); 65 | image.src = dataUrl; 66 | }); -------------------------------------------------------------------------------- /tests/1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Test #1

13 |

Replacing one colors and opacifying.

14 |
15 |
16 |
17 |

Original Image

18 | 19 |
20 |
21 |

Modified Image

22 | 23 |
24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Test #2

13 |

Replacing two colors and opacifying.

14 |
15 |
16 |
17 |

Original Image

18 | 19 |
20 |
21 |

Modified Image

22 | 23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Test #3

13 |

Replace background color with 255,2,0,150

14 |
15 |
16 |
17 |

Original Image

18 | 19 |
20 |
21 |

Modified Image

22 | 23 |
24 |
25 | 26 | 27 | --------------------------------------------------------------------------------