├── Images ├── icon.png ├── favicon.png ├── RowReadOptimized.png ├── ColumnReadOptimized.png ├── RowReadOptimized_small.png ├── ColumnReadOptimized_small.png └── icon.svg ├── LICENSE ├── scripts ├── arrayUtils.js ├── stringConverter.js ├── imageConverter.js └── main.js ├── README.md ├── css └── style.css ├── index.html └── JSArrayTest.html /Images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notisrac/FileToCArray/HEAD/Images/icon.png -------------------------------------------------------------------------------- /Images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notisrac/FileToCArray/HEAD/Images/favicon.png -------------------------------------------------------------------------------- /Images/RowReadOptimized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notisrac/FileToCArray/HEAD/Images/RowReadOptimized.png -------------------------------------------------------------------------------- /Images/ColumnReadOptimized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notisrac/FileToCArray/HEAD/Images/ColumnReadOptimized.png -------------------------------------------------------------------------------- /Images/RowReadOptimized_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notisrac/FileToCArray/HEAD/Images/RowReadOptimized_small.png -------------------------------------------------------------------------------- /Images/ColumnReadOptimized_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notisrac/FileToCArray/HEAD/Images/ColumnReadOptimized_small.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 notisrac 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /scripts/arrayUtils.js: -------------------------------------------------------------------------------- 1 | var arrayUtils = { 2 | /** 3 | * Puts a part of the source array into the destination array. 4 | * This is a much faster replacement for Array.slice and UIntXArray.subArray 5 | * Note: no parameter or error checking! 6 | * It does not return anything, because in javascript every object is passed by reference. So the modifications made in the function are visible on the outside. 7 | */ 8 | subArray : function (sourceArray, destinationArray, startPos, endPos) { 9 | for (var i = startPos; i < endPos; i++) { 10 | destinationArray[i - startPos] = sourceArray[i]; 11 | } 12 | }, 13 | 14 | /** 15 | * Puts the source array at the end of the destination array. 16 | * This is a much faster replacement for Array.concat and UIntXArray.set 17 | * Note: no parameter or error checking! 18 | * It does not return anything, because in javascript every object is passed by reference. So the modifications made in the function are visible on the outside. 19 | */ 20 | concatArray : function (sourceArray, destinationArray, startPos) { 21 | for (var i = 0; i < (sourceArray.length || sourceArray.byteLength); i++) { 22 | destinationArray[startPos + i] = sourceArray[i]; 23 | } 24 | }, 25 | 26 | /** 27 | * Returns true if the object passed in as the parameter is an array 28 | * @param {*} data The object to test 29 | */ 30 | isArray : function (data) { 31 | return (Object.prototype.toString.call(data).indexOf('Array') != -1); 32 | } 33 | 34 | }; 35 | -------------------------------------------------------------------------------- /scripts/stringConverter.js: -------------------------------------------------------------------------------- 1 | var stringConverter = { 2 | convertByte: function (oneByte, bytesPerPixel, conversionType, endianness) { 3 | // console.log(oneByte); 4 | var stringByte = '???'; 5 | 6 | if (conversionType == 'HEX0' || conversionType == 'HEX_SLASH') { 7 | stringByte = oneByte.toString(16).padStart(bytesPerPixel * 2, '0'); 8 | if (endianness == 'be') { 9 | stringByte = this.changeEndianness(stringByte); 10 | } 11 | stringByte = ((conversionType == 'HEX0') ? '0x' : '\\x') + stringByte; 12 | } else if (conversionType == 'DEC') { 13 | stringByte = oneByte; 14 | } else if (conversionType == 'BIN') { 15 | stringByte = 'B' + oneByte.toString(2).padStart(bytesPerPixel * 8, '0'); 16 | } else { 17 | console.error('Unknown conversion type'); 18 | } 19 | 20 | return stringByte; 21 | }, 22 | 23 | convert: function (dataLength, bytesPerPixel, conversionType, multiLine, endianness, colNumber, data) { 24 | var resultString = ''; 25 | for (var i = 0; i < dataLength; i++) { 26 | var stringByte = ''; 27 | // need to use bigint, so we can use 32bit integers (4byte per pixel) 28 | let combinedByte = BigInt("0b00000000000000000000000000000000"); 29 | for (let j = 0; j < bytesPerPixel; j++) { 30 | let pixelByte = BigInt(data[(i * bytesPerPixel) + j]); 31 | if (j != 0) { 32 | combinedByte = combinedByte << BigInt(8); 33 | } 34 | combinedByte = combinedByte | pixelByte; 35 | } 36 | stringByte = this.convertByte(combinedByte, bytesPerPixel, conversionType, endianness) + ', '; 37 | if (multiLine && ((i + 1) % colNumber == 0)) { 38 | stringByte += '\r\n '; 39 | } 40 | 41 | resultString += stringByte; 42 | } 43 | resultString = resultString.substr(0, resultString.lastIndexOf(',')).trim(); 44 | 45 | // add the array definition 46 | // resultString = '// array size is ' + dataLength + '\r\nconst uint8_t data[] = {\r\n ' + resultString + '\r\n};'; 47 | 48 | return resultString; 49 | }, 50 | 51 | changeEndianness: function (val) { 52 | const result = []; 53 | let len = val.length - 2; 54 | while (len >= 0) { 55 | result.push(val.substr(len, 2)); 56 | len -= 2; 57 | } 58 | return result.join(''); 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /Images/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # File to C array converter 2 | Coverts any file to a C style array. 3 | Useful if you want to embed a file (binary, text, image, whatever) into your code! 4 | Use it for your Arduino or other embedded projects. 5 | 6 | Just select a file, specify the array format and click convert. It will give you the contents of the file in the specified format, that you can embed into your code. 7 | Supported formats: 8 | - Hex (0x00) 9 | - Hex with trailing slash (\x00) 10 | - Decimal (000) 11 | - Binary (B00000000) 12 | 13 | ## It can also do image color format and size coversion! 14 | If you select an image file, it will recognise it, and show you the image conversion settings panel. 15 | - Change palette: 16 | - 32 bit RGBA (4bytes/pixel) 17 | - 24bit RGB (3bytes/pixel) 18 | - 16bit RRRRRGGGGGGBBBBB (2byte/pixel) 19 | - 15bit RRRRRGGGGGBBBBBA (2byte/pixel) 20 | - 8bit RRRGGGBB (1byte/pixel) 21 | - 8bit grayscale (1byte/pixel) 22 | - 1bit line art (1bit/pixel) 23 | - Resize the image 24 | - Keep the original aspect ratio 25 | - Modify the sizes freely 26 | 27 | 28 | ## Example 29 | We take Google's favicon: 30 | 31 |  32 | 33 | Convert it down to 16x* size (keeping the aspect ratio), 8bit grayscale, with hex output (0x..), and the result is like this: 34 | ```c 35 | #define FAVICON_HEIGHT 16 36 | #define FAVICON_WIDTH 16 37 | 38 | // array size is 256 39 | static const unsigned char favicon[] PROGMEM = { 40 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xff, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0xfe, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xfd, 0xfe, 0x00, 0x00, 42 | 0x00, 0xfe, 0xfc, 0xff, 0xfa, 0xc1, 0x90, 0x79, 0x79, 0x8f, 0xc0, 0xfa, 0xff, 0xfd, 0xfe, 0x00, 43 | 0x00, 0xfd, 0xff, 0xee, 0x8d, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x9b, 0xff, 0xff, 0xfd, 0x00, 44 | 0xff, 0xfe, 0xfa, 0x8c, 0x76, 0x7a, 0xb7, 0xdf, 0xdf, 0xb7, 0x88, 0xea, 0xff, 0xff, 0xfd, 0xf9, 45 | 0xfd, 0xff, 0xca, 0x79, 0x79, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfd, 46 | 0xfd, 0xff, 0xa8, 0x91, 0xb5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 47 | 0xfd, 0xff, 0x96, 0x94, 0xdf, 0xff, 0xff, 0xff, 0x93, 0x93, 0x93, 0x93, 0x93, 0xb3, 0xff, 0xfd, 48 | 0xfd, 0xff, 0x96, 0x94, 0xdf, 0xff, 0xff, 0xff, 0x93, 0x93, 0x93, 0x93, 0x93, 0xaf, 0xff, 0xfd, 49 | 0xfd, 0xff, 0xa9, 0x8f, 0xb0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb8, 0x93, 0xbd, 0xff, 0xfd, 50 | 0xfd, 0xff, 0xc8, 0x69, 0x68, 0xd9, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x96, 0x93, 0xdc, 0xff, 0xff, 51 | 0xff, 0xfd, 0xfa, 0x7f, 0x65, 0x69, 0xac, 0xd9, 0xdb, 0xb3, 0x7e, 0x92, 0xa8, 0xfd, 0xfd, 0xf9, 52 | 0x00, 0xfd, 0xff, 0xed, 0x80, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x82, 0xf1, 0xff, 0xfd, 0x00, 53 | 0x00, 0xfe, 0xfd, 0xff, 0xfa, 0xba, 0x84, 0x69, 0x69, 0x80, 0xb4, 0xf7, 0xff, 0xfd, 0xff, 0x00, 54 | 0x00, 0x00, 0xfe, 0xfd, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xfd, 0xff, 0x00, 0x00, 55 | 0x00, 0x00, 0x00, 0x00, 0xf9, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xff, 0xf9, 0x00, 0x00, 0x00, 0x00 56 | }; 57 | ``` 58 | 59 | 60 | ## JSArrayTest.html 61 | Tests the speed of different array manipulation techniques in javascript 62 | 63 | 64 | ## See it in acton here [https://notisrac.github.io/FileToCArray](https://notisrac.github.io/FileToCArray) 65 | 66 | 67 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | label { 2 | width: 190px; 3 | margin: 1px; 4 | display: inline-block; 5 | vertical-align: top; 6 | } 7 | 8 | fieldset { 9 | width: 600px; 10 | } 11 | 12 | img { 13 | image-rendering: optimizeSpeed; /* STOP SMOOTHING, GIVE ME SPEED */ 14 | image-rendering: -moz-crisp-edges; /* Firefox */ 15 | image-rendering: -o-crisp-edges; /* Opera */ 16 | image-rendering: -webkit-optimize-contrast; /* Chrome (and eventually Safari) */ 17 | image-rendering: pixelated; /* Chrome */ 18 | image-rendering: optimize-contrast; /* CSS3 Proposed */ 19 | -ms-interpolation-mode: nearest-neighbor; /* IE8+ */ 20 | } 21 | 22 | #imgPreview { 23 | display: inline-block; 24 | max-height: 100px; 25 | min-height: 32px; 26 | border: 1px solid #696969; 27 | } 28 | 29 | .imageConversionOption { 30 | } 31 | 32 | .shortInput { 33 | width: 50px; 34 | } 35 | 36 | /*#divResult > img { 37 | padding-top: 10px; 38 | max-width: 95vw; 39 | } 40 | 41 | #fsResult { 42 | max-width: 96vw; 43 | width: 100%; 44 | } 45 | 46 | #txtResult { 47 | width: 95vw; 48 | height: 500px; 49 | float: left; 50 | font-size: 13px; 51 | }*/ 52 | 53 | #divResult > img { 54 | padding-left: 10px; 55 | max-width: 800px; 56 | } 57 | 58 | #fsResult { 59 | max-width: 1620px; 60 | /*width: 100%;*/ 61 | } 62 | 63 | #txtResult { 64 | width: 800px; 65 | height: 530px; 66 | float: left; 67 | font-size: 13px; 68 | } 69 | 70 | .linkButtons { 71 | text-decoration: none; 72 | } 73 | 74 | .versionInfo { 75 | font-size: 10px; 76 | margin-left: 10px; 77 | font-weight: normal; 78 | } 79 | 80 | .additionalInfo { 81 | margin-top: -20px; 82 | font-weight: normal; 83 | font-size: 14px; 84 | } 85 | 86 | .signaturePreview { 87 | float: right; 88 | font-family: 'Courier New', Courier, monospace; 89 | font-size: 12px; 90 | padding-top: 4px; 91 | color: #696969; 92 | } 93 | 94 | /* Tooltip container */ 95 | .tooltip { 96 | position: relative; 97 | display: inline-block; 98 | width: 16px; 99 | height: 16px; 100 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAPUExURQAAAAAAAAAAAAAAAAAAAE8O540AAAAFdFJOUwAyIhcHOGe1IAAAAFdJREFUGNNlj1ECwCAIQgW5/5lHaas1vvSpqBGWkgRT0UqAFpCVu6gVVD13q0MVBqpHptog3ELGIWdrAu3bIDYgPoC3KXstymSs/R32XnwE93Pz/cGm+wN52wDgRMjGVQAAAABJRU5ErkJggg==); 101 | top: 2px; 102 | } 103 | 104 | /* Tooltip text */ 105 | .tooltip .tooltiptext { 106 | visibility: hidden; 107 | min-width: 300px; 108 | max-width: 600px; 109 | background-color: #EEE; 110 | color: #000; 111 | border: 1px solid #696969; 112 | text-align: left; 113 | padding: 5px; 114 | border-radius: 6px; 115 | 116 | /* Position the tooltip text - see examples below! */ 117 | position: absolute; 118 | z-index: 1; 119 | top: -5px; 120 | left: 150%; 121 | 122 | font-size: 12px; 123 | } 124 | 125 | /* Show the tooltip text when you mouse over the tooltip container */ 126 | .tooltip:hover .tooltiptext { 127 | visibility: visible; 128 | } 129 | 130 | .tooltip .tooltiptext::after { 131 | content: " "; 132 | position: absolute; 133 | top: 13px; 134 | right: 100%; 135 | margin-top: -5px; 136 | border-width: 5px; 137 | border-style: solid; 138 | border-color: transparent black transparent transparent; 139 | } 140 | 141 | .image1BitModeOnly { 142 | } -------------------------------------------------------------------------------- /scripts/imageConverter.js: -------------------------------------------------------------------------------- 1 | var imageConverter = { 2 | /** 3 | * Converts a pixel from 24bit (RGBA) to the specified format. 4 | * It also returns the modified pixels in 24bit format, so it can be displayed again 5 | */ 6 | convertFromPixel: function (pixelData, mode) { 7 | // the converted pixel values 8 | var retData = new Array(); 9 | var r = pixelData[0]; 10 | var g = pixelData[1]; 11 | var b = pixelData[2]; 12 | var a = pixelData[3]; 13 | var newR = 0; 14 | var newG = 0; 15 | var newB = 0; 16 | // the converted pixel in 24bit format (rgba) 17 | var newPixelData = new Array(4); 18 | switch (mode) { 19 | case '32': 20 | retData = [r, g, b, a]; 21 | newPixelData = [r, g, b, a]; 22 | break; 23 | case '32r': 24 | retData = [b, g, r, a]; 25 | newPixelData = [r, g, b, a]; 26 | break; 27 | case '24': 28 | retData = [r, g, b]; 29 | newPixelData = [r, g, b, 255]; 30 | break; 31 | case '16': 32 | // 1 2 3 4 5 6 7 8|1 2 3 4 5 6 7 8 33 | // R R R R R|G G G G G G|B B B B B 34 | // 1 2 3 4 5|1 2 3 4 5 6|1 2 3 4 5 35 | // 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 36 | // 0000100000100001 37 | // R, B = 32 values 38 | // G = 64 values 39 | newR = (r * 32 / 256) | 0; // Math.floor() 40 | newG = (g * 64 / 256) | 0; 41 | newB = (b * 32 / 256) | 0; 42 | var b16Pixel = newR * 2048 + newG * 32 + newB; 43 | retData = [b16Pixel >> 8, b16Pixel & 255]; // RRRRRGGG|GGGBBBBB 44 | newPixelData = [newR * 256 / 32, newG * 256 / 64, newB * 256 / 32, 255]; // scale the values back to the 0-255 range 45 | break; 46 | case '16bgr': 47 | // 1 2 3 4 5 6 7 8|1 2 3 4 5 6 7 8 48 | // B B B B B|G G G G G G|R R R R R 49 | // 1 2 3 4 5|1 2 3 4 5 6|1 2 3 4 5 50 | // 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 51 | // 0000100000100001 52 | // R, B = 32 values 53 | // G = 64 values 54 | newR = (r * 32 / 256) | 0; // Math.floor() 55 | newG = (g * 64 / 256) | 0; 56 | newB = (b * 32 / 256) | 0; 57 | var b16Pixel = newB * 2048 + newG * 32 + newR; 58 | retData = [b16Pixel >> 8, b16Pixel & 255]; // BBBBBGGG|GGGRRRRR 59 | newPixelData = [newB * 256 / 32, newG * 256 / 64, newR * 256 / 32, 255]; // scale the values back to the 0-255 range 60 | break; 61 | case '15': 62 | newR = (r * 32 / 256) | 0; // Math.floor() 63 | newG = (g * 32 / 256) | 0; 64 | newB = (b * 32 / 256) | 0; 65 | var newA = (a > 0) ? 1 : 0; 66 | var b15Pixel = newR * 2048 + newG * 64 + newB * 2 + newA; 67 | retData = [b15Pixel >> 8, b15Pixel & 255]; // RRRRRGGG|GGBBBBBA 68 | newPixelData = [newR * 256 / 32, newG * 256 / 32, newB * 256 / 32, (newA == 1) ? 255 : 0]; // scale the values back to the 0-255 range 69 | break; 70 | case '8': 71 | // 1 2 3 4 5 6 7 8 72 | // R R R|G G G|B B 73 | // 1 2 3|1 2 3|1 2 74 | // 0 0 1 0 0 1 0 1 75 | // R, G = 8 values 76 | // B = 4 values 77 | //retData = [Math.floor((r * 6 / 256) * 36 + (g * 6 / 256) * 6 + (b * 6 / 256))]; // http://stackoverflow.com/a/12808927 78 | //newR = (r * 6 / 256); 79 | //newG = (g * 6 / 256); 80 | //newB = (b * 6 / 256); 81 | //retData = [Math.floor(newR * 36 + newG * 6 + newB)]; 82 | newR = (r * 8 / 256) | 0; 83 | newG = (g * 8 / 256) | 0; 84 | newB = (b * 4 / 256) | 0; 85 | retData = [newR * 32 + newG * 4 + newB]; // RRRGGGBB 86 | newPixelData = [newR * 256 / 8, newG * 256 / 8, newB * 256 / 4, 255]; // scale the values back to the 0-255 range 87 | break; 88 | case '8G': 89 | // http://www.ajaxblender.com/howto-convert-image-to-grayscale-using-javascript.html 90 | newR = ((r + g + b) / 3) | 0; 91 | retData = [newR]; 92 | newPixelData = [newR, newR, newR, 255]; 93 | break; 94 | case '1': 95 | var b1Pixel = ((r * 0.3 + g * 0.59 + b * 0.11) > 127) ? 1 : 0; // http://stackoverflow.com/a/18707438 96 | retData = [b1Pixel]; 97 | newPixelData = [b1Pixel * 255, b1Pixel * 255, b1Pixel * 255, 255]; 98 | break; 99 | default: 100 | } 101 | 102 | return { convertedPixel: retData, newPixel: newPixelData }; 103 | }, 104 | 105 | getBits: function (byteValue) { 106 | var outBits = ''; 107 | for (let i = 0; i < 8; i++) { 108 | var bitMask = 1 << i; 109 | if ((byteValue & bitMask) != 0) { 110 | outBits += '1'; 111 | } else { 112 | outBits += '0'; 113 | } 114 | } 115 | //console.log(outBits); 116 | 117 | return outBits; 118 | }, 119 | 120 | getConvertedPixel: function (source, position, paletteMod) { 121 | // single pixel from the original set 122 | var pixelData = new Uint8Array(4); 123 | // get the current pixel (4 bytes) 124 | arrayUtils.subArray(source, pixelData, position, position + 4); 125 | // modify the current pixel 126 | var moddedPixelData = this.convertFromPixel(pixelData, paletteMod); 127 | 128 | return moddedPixelData; 129 | }, 130 | 131 | convert: function (imageWidth, imageHeight, bytePerPixel, paletteMod, origPixels, forColumnRead) { 132 | // the downsampled pixels 133 | var moddedPixels = new Uint8Array(imageWidth * imageHeight * bytePerPixel); // typed arrays are way faster, than the genric Array 134 | // the actual length of the modded pixels array 135 | var moddedPixelsActualLength = (paletteMod == '1') ? 0 : moddedPixels.length; 136 | // the downsampled pixels converted back to 24bit for displaying 137 | var newPixels = new Uint8ClampedArray(imageWidth * imageHeight * 4); 138 | // loop through all the pixels, and modify them one by one 139 | if (!forColumnRead || (forColumnRead && paletteMod != '1')) { 140 | for (var i = 0; i < (origPixels.byteLength/*image.height * image.width * 4*/); i += 4) { 141 | // modify the current pixel 142 | var moddedPixelData = this.getConvertedPixel(origPixels, i, paletteMod); 143 | // store the new pixel 144 | arrayUtils.concatArray(moddedPixelData.newPixel, newPixels, i); 145 | // store the modified pixel 146 | if (paletteMod == '1') { // this one is tricky: every 8 pixels make up a byte 147 | var itemNo = Math.floor(i / 4 / 8); 148 | var currentBitPos = 7 - (i / 4) % 8; 149 | moddedPixels[itemNo] = (moddedPixels[itemNo] & (~(1 << currentBitPos))) | (moddedPixelData.convertedPixel[0] << currentBitPos) 150 | 151 | if (itemNo > moddedPixelsActualLength) { 152 | moddedPixelsActualLength = itemNo + 1; 153 | } 154 | } 155 | else { // the convertFromPixel returns an array 156 | arrayUtils.concatArray(moddedPixelData.convertedPixel, moddedPixels, i / 4 * bytePerPixel); 157 | } 158 | } 159 | } else { 160 | var byteCount = 0; 161 | var yPos = 0; 162 | do { 163 | var yStop = 8; 164 | if (yPos + 8 > imageHeight) { 165 | yStop = imageHeight - yPos; 166 | } 167 | for (let x = 0; x < imageWidth; x++) { 168 | var outValue = 0; 169 | for (let y = 0; y < yStop; y++) { 170 | var pixelPos = ((yPos + y) * imageWidth * 4) + (x * 4); 171 | //console.log(x + ',' + y + '(' + yPos + '): ' + pixelPos); 172 | 173 | // modify the current pixel 174 | var moddedPixelData = this.getConvertedPixel(origPixels, pixelPos, paletteMod); 175 | // store the new pixel 176 | arrayUtils.concatArray(moddedPixelData.newPixel, newPixels, pixelPos); 177 | var pixelValue = moddedPixelData.convertedPixel[0]; 178 | // console.log('pixelPos:' + pixelPos + ' outValue:' + this.getBits(outValue) + ' pixelValue:' + JSON.stringify(pixelValue)); 179 | 180 | // add the pixels to the byte 181 | var mask = 1 << (y % 8); 182 | if (0 < pixelValue) { 183 | outValue |= mask; 184 | } 185 | else { 186 | outValue &= ~mask; 187 | } 188 | // console.log('x:' + x + ' y:' + y + ' pixelValue:' + pixelValue + ' outValue:' + this.getBits(outValue)); 189 | } 190 | // switch to a new byte 191 | arrayUtils.concatArray([outValue], moddedPixels, byteCount); 192 | // console.log(byteCount + ': ' + this.getBits(outValue)); 193 | // console.log(byteCount + ': ' + JSON.stringify(moddedPixels)); 194 | byteCount++; 195 | } 196 | yPos += yStop; 197 | } while (yPos < imageHeight); 198 | 199 | moddedPixelsActualLength = byteCount; 200 | } 201 | 202 | if (moddedPixels.length != moddedPixelsActualLength) { 203 | console.log('array length: ' + moddedPixels.length + ' -> ' + moddedPixelsActualLength); 204 | var tmp = new Uint8Array(moddedPixelsActualLength); 205 | arrayUtils.subArray(moddedPixels, tmp, 0, tmp.length); 206 | moddedPixels = tmp; 207 | } 208 | // moddedPixels: this is the actual data, that will be displayed as the array 209 | // newPixels: this will be displayed as the converted image 210 | return { moddedPixels: moddedPixels, newPixels: newPixels }; 211 | 212 | } 213 | }; 214 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 13 | 14 |36 | Select a file: 37 |
38 | 69 | 204 |205 | 206 |
207 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /scripts/main.js: -------------------------------------------------------------------------------- 1 | ///