Files
image2cpp/script.js
T
2016-01-22 15:46:51 +01:00

430 lines
11 KiB
JavaScript

// Add events to the file input button
var fileInput = document.getElementById('fileInput');
fileInput.addEventListener('click', function(){this.value = null;}, false);
fileInput.addEventListener('change', handleImageSelection, false);
// Filetypes accepted by the file picker
var fileTypes = ['jpg', 'jpeg', 'png', 'bmp', 'gif'];
// The canvas we will draw on
var canvas = document.getElementById('imageCanvas');
var ctx = canvas.getContext('2d');
// The variable to hold our image. Global so we can easily reuse it when the
// user updates the settings (change canvas size, scale, invert, etc)
var img = new Image();
// A bunch of settings used when converting
var settings = {
screenWidth: 128,
screenHeight: 64,
scaleToFit: true,
preserveRatio: true,
centerHorizontally: false,
centerVertically: false,
backgroundColor: "white",
scale: '1',
drawMode: 'horizontal',
threshold: 128,
addArduinoCode: false,
invertColors: false
};
// Easy way to update settings controlled by a textfield
function updateInteger(fieldName){
settings[fieldName] = document.getElementById(fieldName).value;
place_image();
}
// Easy way to update settings controlled by a checkbox
function updateBoolean(fieldName){
settings[fieldName] = document.getElementById(fieldName).checked;
place_image();
}
// Easy way to update settings controlled by a radiobutton
function updateRadio(fieldName){
var radioGroup = document.getElementsByName(fieldName);
for (var i = 0; i < radioGroup.length; i++) {
if (radioGroup[i].checked) {
settings[fieldName] = radioGroup[i].value;
}
}
place_image();
}
// Make the canvas black and white
function blackAndWhite(){
var imageData = ctx.getImageData(0,0,canvas.width, canvas.height);
var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
var avg = (data[i] + data[i +1] + data[i +2]) / 3;
avg > settings['threshold'] ? avg = 255 : avg = 0;
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
}
ctx.putImageData(imageData, 0, 0);
};
// Invert the colors of the canvas
function invert() {
var imageData = ctx.getImageData(0,0,canvas.width, canvas.height);
var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // red
data[i + 1] = 255 - data[i + 1]; // green
data[i + 2] = 255 - data[i + 2]; // blue
}
ctx.putImageData(imageData, 0, 0);
};
// Draw the image onto the canvas, taking into account color and scaling
function place_image(){
// Make sure we're using the right canvas size
canvas.width = settings['screenWidth'];
canvas.height = settings['screenHeight'];
// Invert background if needed
if (settings['invertColors']){
settings['backgroundColor'] == 'white' ? ctx.fillStyle = 'black' : ctx.fillStyle = 'white';
}else{
ctx.fillStyle = settings['backgroundColor'];
}
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Offset used for centering the image when requested
var offset_x = 0;
var offset_y = 0;
switch(settings['scale']){
case '1': // Original
if(settings['centerHorizontally']){ offset_x = (canvas.width - img.width) / 2; }
if(settings['centerVertically']){ offset_y = (canvas.height - img.height) / 2; }
ctx.drawImage(img, 0, 0, img.width, img.height,
offset_x, offset_y, img.width, img.height);
break;
case '2': // Fit (make as large as possible without changing ratio)
var horRatio = canvas.width / img.width;
var verRatio = canvas.height / img.height;
var useRatio = Math.min(horRatio, verRatio);
if(settings['centerHorizontally']){ offset_x = (canvas.width - img.width*useRatio) / 2; }
if(settings['centerVertically']){ offset_y = (canvas.height - img.height*useRatio) / 2; }
ctx.drawImage(img, 0, 0, img.width, img.height,
offset_x, offset_y, img.width * useRatio, img.height * useRatio);
break;
case '3': // Stretch x+y (make as large as possible without keeping ratio)
ctx.drawImage(img, 0, 0, img.width, img.height,
offset_x, offset_y, canvas.width, canvas.height);
break;
case '4': // Stretch x (make as wide as possible)
offset_x = 0;
if(settings['centerVertically']){ offset_y = (canvas.height - img.height) / 2; }
ctx.drawImage(img, 0, 0, img.width, img.height,
offset_x, offset_y, canvas.width, img.height);
break;
case '5': // Stretch y (make as tall as possible)
if(settings['centerHorizontally']){ offset_x = (canvas.width - img.width) / 2; }
offset_y = 0;
ctx.drawImage(img, 0, 0, img.width, img.height,
offset_x, offset_y, img.width, canvas.height);
break;
}
// Make sure the image is black and white
blackAndWhite();
if(settings['invertColors']){
invert();
}
}
// Handle inserting an image by pasting code
function handleTextInput(drawMode){
var input = document.getElementById('textInput').value;
// Remove Arduino code
input = input.replace(/const unsigned char myBitmap \[\] PROGMEM = \{/g, "");
input = input.replace(/\};/g, "");
// Remove newlines
input = input.replace(/\r\n|\r|\n/g, "");
// Remove whitespace
input = input.replace(/\s/g, "");
// Remove "0x"
input = input.replace(/0x/g, "");
// Split into list
var list = input.split(",");
if(drawMode == 'horizontal'){
listToImageHorizontal(list);
}else{
listToImageVertical(list);
}
}
// Handle selecting an image with the file picker
function handleImageSelection(e){
var reader = new FileReader();
reader.onload = function(event){
// Crude check to see if the uploaded file is an image
if (reader.result.substring (0, 10) != "data:image"){
alert("Please select an image file.");
return false;
}
img.onload = function(){
// Show the size underneath the file picker
document.getElementById('imageSize').innerHTML = img.width+" * " + img.height + " pixels";
// Resize the canvas and update the input fields
document.getElementById('screenWidth').value = img.width;
document.getElementById('screenHeight').value = img.height;
settings['screenWidth'] = img.width;
settings['screenHeight'] = img.height;
place_image();
}
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
// Output the image as a string for horizontally drawing displays
function imageToStringHorizontal(){
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var output_string = "";
var output_index = 0;
var byteIndex = 7;
var number = 0;
for (var index=0; index < imageData.data.length; index+=4){
var avg = (imageData.data[index] + imageData.data[index +1] + imageData.data[index +2]) / 3;
if (avg > settings['threshold']){
number += Math.pow(2, byteIndex);
}
byteIndex--;
if(byteIndex < 0){
var byteSet = number.toString(16);
if (byteSet.length == 1){ byteSet = "0"+byteSet; }
var b = "0x"+byteSet;
output_string += b+", ";
output_index++;
if (output_index >= 16){
output_string += "\n";
output_index = 0;
}
number = 0;
byteIndex = 7;
}
}
return output_string;
}
// Output the image as a string for vertically drawing displays
function imageToStringVertical(){
var x = 0;
var y = 7;
var page = 0;
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
var output_string = "";
var output_index = 0;
for (var p=0; p<Math.ceil(settings['screenHeight']/8);p++){
for (var x=0;x<=settings['screenWidth'];x++){
// for (var x=0;x<1;x++){
var byteIndex = 7;
var number = 0;
for (var y = 7; y >= 0; y--){
var index = ((p*8)+y)*(settings['screenWidth']*4)+x;
var avg = (data[index] + data[index +1] + data[index +2]) / 3;
if (avg > settings['threshold']){
number += Math.pow(2, byteIndex);
}
byteIndex--;
}
var byteSet = number.toString(16);
if (byteSet.length == 1){ byteSet = "0"+byteSet; }
var b = "0x"+byteSet.toString(16);
output_string += b+", ";
output_index++;
if (output_index >= 16){
output_string += "\n";
output_index = 0;
}
}
}
return output_string;
}
// Output the image string to the textfield
function outputString(){
var output_string = "";
if (settings['drawMode'] == 'horizontal'){
output_string = imageToStringHorizontal();
}else{
output_string = imageToStringVertical();
}
if(settings['addArduinoCode']){
output_string = "const unsigned char myBitmap [] PROGMEM = {\n" + output_string + "\n};";
}
document.getElementById('outputField').value = output_string;
}
// Use the horizontally oriented list to draw the image
function listToImageHorizontal(list){
ctx.clearRect(0, 0, canvas.width, canvas.height);
var imgData = ctx.createImageData(canvas.width, canvas.height);
var index = 0;
var page = 0;
var x = 0;
var y = 7;
// Move the list into the imageData object
for (var i=0;i<list.length;i++){
var binString = hexToBinary(list[i]).result;
if (binString.length == 4){
binString = binString + "0000";
}
// Check if pixel is white or black
for(var k=0; k<binString.length; k++){
var color = 0;
if(binString.charAt(k) == '1'){
color = 255;
}
imgData.data[index] = color;
imgData.data[index+1] = color;
imgData.data[index+2] = color;
imgData.data[index+3] = 255;
index += 4
}
}
// Draw the image onto the canvas, then save the canvas contents
// inside the img object. This way we can reuse the img object when
// we want to scale / invert, etc.
ctx.putImageData(imgData, 0, 0);
img.src = canvas.toDataURL('image/png');
}
// Use the vertically oriented list to draw the image
function listToImageVertical(list){
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Create a new imageData object, but 90 degrees rotates (height x width)
// var imgData = ctx.createImageData(canvas.width, canvas.height);
// var imgData = ctx.getImageData(0, 0, canvas.height, canvas.width);
//var imgData = ctx.createImageData(canvas.width, canvas.height);
// var data = imgData.data;
var index = 0;
var page = 0;
var x = 0;
var y = 7;
// Move the list into the imageData object
for (var i=0;i<list.length;i++){
var binString = hexToBinary(list[i]).result;
if (binString.length == 4){
binString = binString + "0000";
}
// Check if pixel is white or black
for(var k=0; k<binString.length; k++){
var color = 0;
if(binString.charAt(k) == '1'){
color = 255;
}
// color = 0;
drawPixel(x, (page*8)+y, color);
y--;
if(y < 0){
y = 7;
x++;
if(x >= settings['screenWidth']){
x = 0;
page++;
}
}
}
}
// Save the canvas contents inside the img object. This way we can
// reuse the img object when we want to scale / invert, etc.
img.src = canvas.toDataURL('image/png');
}
// Convert hex to binary
function hexToBinary(s) {
var i, k, part, ret = '';
// lookup table for easier conversion. '0' characters are padded for '1' to '7'
var lookupTable = {
'0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100',
'5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001',
'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101',
'e': '1110', 'f': '1111',
'A': '1010', 'B': '1011', 'C': '1100', 'D': '1101',
'E': '1110', 'F': '1111'
};
for (i = 0; i < s.length; i += 1) {
if (lookupTable.hasOwnProperty(s[i])) {
ret += lookupTable[s[i]];
} else {
return { valid: false };
}
}
return { valid: true, result: ret };
}
// Quick and effective way to draw single pixels onto the canvas
// using a global 1x1px large canvas
var single_pixel = ctx.createImageData(1,1);
var d = single_pixel.data;
function drawPixel(x, y, color){
d[0] = color;
d[1] = color;
d[2] = color;
d[3] = 255;
ctx.putImageData(single_pixel, x, y);
}