From bdcc5570709212897da53e6c29a04e2b3d9b852d Mon Sep 17 00:00:00 2001 From: javl Date: Fri, 22 Jan 2016 14:46:03 +0100 Subject: [PATCH 1/9] Initial commit --- README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 From 2a635f471b616ce0e942836f8a42f530bc0fae6c Mon Sep 17 00:00:00 2001 From: javl Date: Fri, 22 Jan 2016 15:04:54 +0100 Subject: [PATCH 2/9] First version of the tool --- img/error.jpg | Bin 0 -> 7330 bytes index.html | 122 ++++++++++++++ script.js | 431 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 553 insertions(+) create mode 100644 img/error.jpg create mode 100644 index.html create mode 100644 script.js diff --git a/img/error.jpg b/img/error.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9109b259bdd7801b2991c0a7ca827a0ec2d2c266 GIT binary patch literal 7330 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 + + + + image2cpp + + + +
+

+ + + + + +
+

Select image

+
+ - + +
or +

Paste text

+
+ + +
+

+
+ +

+

Image Settings

+ * pixels
+ + +
+ 0 - 255; pixels with brightness above become white, below become black.
+ +
+ +
+
+ Centering the image is only relevant when using a canvas larger than the selected image.
+ +

+ +
+ +

+

Preview

+ +

+ +
+ +

+

Output

+
+ Adds some extra Arduino code around the output for easy copy-paste into this example.
+
+ + +
+ If your image looks all messed up on your display, like the image below, try the other mode.
+
+

+

+ +

+
+ + + + diff --git a/script.js b/script.js new file mode 100644 index 0000000..0d745be --- /dev/null +++ b/script.js @@ -0,0 +1,431 @@ + +// 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; + if (settings['invertColors']){ + avg > settings['threshold'] ? avg = 0 : avg = 255; + }else{ + 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 colors 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(); +} + + +// 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= 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= 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); +} \ No newline at end of file From df6977d00299257e10c68ed722325a79c47a9ec3 Mon Sep 17 00:00:00 2001 From: javl Date: Fri, 22 Jan 2016 15:06:33 +0100 Subject: [PATCH 3/9] Updates readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e69de29..8687f07 100644 --- a/README.md +++ b/README.md @@ -0,0 +1 @@ +Simple tool to create byte arrays from images to be used with small screens such as OLEDs. From 20ba5c40ecfc0816f8c0c8d402b0b50f5793303c Mon Sep 17 00:00:00 2001 From: javl Date: Fri, 22 Jan 2016 15:43:55 +0100 Subject: [PATCH 4/9] Adds Arduino example, updates script --- index.html | 23 ++++++---- oled_example/oled_example.ino | 82 +++++++++++++++++++++++++++++++++++ script.js | 11 +++-- 3 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 oled_example/oled_example.ino diff --git a/index.html b/index.html index c4303b8..1e36618 100644 --- a/index.html +++ b/index.html @@ -9,6 +9,7 @@ } .wrapper{ width: 800px; + margin: auto; } .numberInput{ width: 50px; @@ -32,7 +33,7 @@ /*vertical-align: center;*/ } hr{ - height: 1px; + height: 3px; background-color: black; border: none; } @@ -46,21 +47,25 @@ table{ width: 100%; } + h1{ + margin: 0; + }
+

image2cpp

-

Select image

+

1. Select image


- - + no image selected
or -

Paste text

+

1. Paste byte array


@@ -71,7 +76,7 @@

-

Image Settings

+

2. Image Settings

* pixels
@@ -80,7 +85,7 @@

- Centering the image is only relevant when using a canvas larger than the selected image.
+ Centering the image only works when using a canvas larger than the selected image.


-

Preview

+

3. Preview


-

Output

+

4. Output


Adds some extra Arduino code around the output for easy copy-paste into this example.

diff --git a/oled_example/oled_example.ino b/oled_example/oled_example.ino new file mode 100644 index 0000000..64bab16 --- /dev/null +++ b/oled_example/oled_example.ino @@ -0,0 +1,82 @@ +/********************************************************************* +This is an example for Adafuit's Monochrome OLEDs based on SSD1306 drivers + + Pick one up today in the adafruit shop! + ------> http://www.adafruit.com/category/63_98 + +This example is for a 128x64 size display using I2C to communicate +3 pins are required to interface (2 I2C and one reset) + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information +All text above, and the splash screen must be included in any redistribution +*********************************************************************/ + +#include +#include +#include +#include + +#define OLED_RESET 4 +Adafruit_SSD1306 display(OLED_RESET); + +#if (SSD1306_LCDHEIGHT != 64) +#error("Height incorrect, please fix Adafruit_SSD1306.h!"); +#endif +const unsigned char myBitmap [] PROGMEM = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, +0x0f, 0xbe, 0xf7, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x02, 0x20, 0x81, 0x00, 0x00, 0x00, 0x01, 0xc0, +0x02, 0x3e, 0xf1, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x02, 0x20, 0x11, 0x00, 0x00, 0x00, 0x0e, 0x00, +0x02, 0x20, 0x11, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x02, 0x3e, 0xf1, 0x00, 0x00, 0x00, 0x0e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, +0x00, 0x00, 0x00, 0x07, 0xfe, 0x03, 0x80, 0x00, 0x0f, 0xfe, 0x00, 0x08, 0x01, 0x03, 0x80, 0x00, +0x0f, 0xfe, 0x00, 0x14, 0x02, 0x80, 0x70, 0x00, 0x0f, 0xfe, 0x00, 0x12, 0x04, 0x80, 0x70, 0x00, +0x0e, 0x0e, 0x00, 0x11, 0x08, 0x80, 0x70, 0x00, 0x0e, 0x0e, 0x00, 0x10, 0xf0, 0x80, 0x0e, 0x00, +0x0e, 0x0e, 0x00, 0x10, 0x90, 0x80, 0x0e, 0x00, 0x0e, 0x0e, 0x00, 0x10, 0x90, 0x80, 0x0e, 0x00, +0x0f, 0xfe, 0x00, 0x10, 0xf0, 0x80, 0x01, 0xc0, 0x0f, 0xfe, 0x00, 0x11, 0x08, 0x80, 0x01, 0xc0, +0x0f, 0xfe, 0x00, 0x12, 0x04, 0x80, 0x01, 0xc0, 0x0e, 0x0e, 0x00, 0x14, 0x02, 0x80, 0x00, 0x38, +0x0e, 0x0e, 0x00, 0x08, 0x01, 0x00, 0x00, 0x38, 0x0e, 0x0e, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x38, +0x0e, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +0x0e, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x0e, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + +}; +void setup() { + // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) + display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128x64) + // If the screen doesn't update, try using 0x3C instead + + display.clearDisplay(); // Make sure the display is cleared + // Draw the bitmap: + // drawBitmap(x position, y position, bitmap data, bitmap width, bitmap height, color) + display.drawBitmap(0, 0, myBitmap, 64, 64, WHITE); + + // Update the display + display.display(); +} + + +void loop() { + +} diff --git a/script.js b/script.js index 0d745be..361265c 100644 --- a/script.js +++ b/script.js @@ -68,11 +68,7 @@ function blackAndWhite(){ var data = imageData.data; for (var i = 0; i < data.length; i += 4) { var avg = (data[i] + data[i +1] + data[i +2]) / 3; - if (settings['invertColors']){ - avg > settings['threshold'] ? avg = 0 : avg = 255; - }else{ - avg > settings['threshold'] ? avg = 255 : avg = 0; - } + avg > settings['threshold'] ? avg = 255 : avg = 0; data[i] = avg; // red data[i + 1] = avg; // green data[i + 2] = avg; // blue @@ -101,7 +97,7 @@ function place_image(){ canvas.width = settings['screenWidth']; canvas.height = settings['screenHeight']; - // Invert colors if needed + // Invert background if needed if (settings['invertColors']){ settings['backgroundColor'] == 'white' ? ctx.fillStyle = 'black' : ctx.fillStyle = 'white'; }else{ @@ -149,6 +145,9 @@ function place_image(){ } // Make sure the image is black and white blackAndWhite(); + if(settings['invertColors']){ + invert(); + } } From bd79c5baeb31722ac7591b61d2ec3ac3003c7358 Mon Sep 17 00:00:00 2001 From: javl Date: Fri, 22 Jan 2016 15:44:53 +0100 Subject: [PATCH 5/9] Add link to example file --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 1e36618..607fd74 100644 --- a/index.html +++ b/index.html @@ -109,7 +109,7 @@

4. Output


- Adds some extra Arduino code around the output for easy copy-paste into this example.
+ Adds some extra Arduino code around the output for easy copy-paste into this example.

From 82c64f4fb7103ab19c97fa16c6e9291e8223003e Mon Sep 17 00:00:00 2001 From: javl Date: Fri, 22 Jan 2016 15:59:07 +0100 Subject: [PATCH 6/9] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8687f07..7cb6820 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ Simple tool to create byte arrays from images to be used with small screens such as OLEDs. + +Use the converter at: http://javl.github.io/image2cpp/ From 32aa787bf9fe7b6dd679e623a8f129e111c9bb8e Mon Sep 17 00:00:00 2001 From: javl Date: Mon, 25 Jan 2016 16:33:17 +0100 Subject: [PATCH 7/9] Update README.md --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7cb6820..c1b260f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,15 @@ -Simple tool to create byte arrays from images to be used with small screens such as OLEDs. +## image2cpp ## -Use the converter at: http://javl.github.io/image2cpp/ +image2cpp is a simple tool to change images into byte arrays to use with (monochrome) displays suchs as OLEDs, like those from Adafruit or Sparkfun. While searching for a way to generate these arrays, I mostly found links to a piece of Windows software. Both the flakey results and the hassle of having to boot a virtual machine just to convert an image lead to me writing this pure html + javascript solution. + +Alternatively you can also enter a byte array as input to turn it back into an image. This might be useful for debugging, or when you want to write the byte array yourself. I don't know. + +### running the tool ### +You don't need any special dependencies / internet connection; all the necessary parts sit in a single .html file. So just open this index.html page in a (recent) browser to run the tool. +Or you can use the online version at: http://javl.github.io/image2cpp/ + +### Example Arduino code ### +You can find a simple Arduino example sketch [over here](https://github.com/javl/image2cpp/blob/master/oled_example/oled_example.ino) in the repository. + +### Screen types ### +I wrote the code with my 128x64 pixel monochrome OLED display in mind, but it should work with most similar displays. You might need to change some export settings; those are explained in the tool. From 414a106e58382e8ae819752bae9f359d8e9c7ef4 Mon Sep 17 00:00:00 2001 From: javl Date: Mon, 25 Jan 2016 16:35:25 +0100 Subject: [PATCH 8/9] Merged all code (HTML, CSS, JS) into a single .html file --- index.html | 657 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 544 insertions(+), 113 deletions(-) diff --git a/index.html b/index.html index 607fd74..0d29e21 100644 --- a/index.html +++ b/index.html @@ -1,127 +1,558 @@ - - image2cpp - + + image2cpp + -
-

image2cpp

-

- - - - - -
-

1. Select image

-
- no image selected - -
or -

1. Paste byte array

-
- - -
-

-
+
+

image2cpp

+

+ + + + + +
+

1. Select image

+
+ no image selected + +
or +

1. Paste byte array

+
+ + +
+

+
-

-

2. Image Settings

- * pixels
- - -
- 0 - 255; pixels with brightness above become white, below become black.
- -
+

+

2. Image Settings

+ * pixels
+ + +
+ 0 - 255; pixels with brightness above become white, below become black.
+ +
-
-
- Centering the image only works when using a canvas larger than the selected image.
- -

+
+
+ Centering the image only works when using a canvas larger than the selected image.
+ +

-
+
-

-

3. Preview

- -

+

+

3. Preview

+ +

-
+
-

-

4. Output

-
- Adds some extra Arduino code around the output for easy copy-paste into this example.
-
- - -
- If your image looks all messed up on your display, like the image below, try the other mode.
-
-

-

- -

-
- +

+

4. Output

+
+ Adds some extra Arduino code around the output for easy copy-paste into this example.
+
+ + +
+ If your image looks all messed up on your display, like the image below, try the other mode.
+
+

+

+ +

+
+ From bdca2100fc68a7c6a12d1caf9ce2c02a7d7cd8d0 Mon Sep 17 00:00:00 2001 From: javl Date: Mon, 25 Jan 2016 16:38:55 +0100 Subject: [PATCH 9/9] Minor example update --- oled_example/oled_example.ino | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/oled_example/oled_example.ino b/oled_example/oled_example.ino index 64bab16..a2dc819 100644 --- a/oled_example/oled_example.ino +++ b/oled_example/oled_example.ino @@ -63,9 +63,10 @@ const unsigned char myBitmap [] PROGMEM = { }; void setup() { - // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) - display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128x64) - // If the screen doesn't update, try using 0x3C instead + // On my display, I had to used 0x3C as the address, something to do with the RESET not being + // connected to the Arduino. THe 0x3D address below is the address used in the original + // Adafruit OLED example + display.begin(SSD1306_SWITCHCAPVCC, 0x3D); // initialize with the I2C addr 0x3D (for the 128x64) display.clearDisplay(); // Make sure the display is cleared // Draw the bitmap: