mirror of
https://github.com/javl/image2cpp.git
synced 2026-09-11 17:13:20 +00:00
Merge branch 'master' into gh-pages
Conflicts: README.md index.html
This commit is contained in:
@@ -1 +1,15 @@
|
||||
Simple tool to create byte arrays from images to be used with small screens such as OLEDs.
|
||||
## 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.
|
||||
+544
-113
@@ -1,127 +1,558 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>image2cpp</title>
|
||||
<style type="text/css">
|
||||
body{
|
||||
font-family: arial;
|
||||
}
|
||||
.wrapper{
|
||||
width: 800px;
|
||||
margin: auto;
|
||||
}
|
||||
.numberInput{
|
||||
width: 50px;
|
||||
}
|
||||
label{
|
||||
width: 220px;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
}
|
||||
label.smallLabel{
|
||||
width: auto;
|
||||
}
|
||||
td{
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
td.or{
|
||||
padding: 20px;
|
||||
width: 100px;
|
||||
font-size: 30px;
|
||||
/*vertical-align: center;*/
|
||||
}
|
||||
hr{
|
||||
height: 3px;
|
||||
background-color: black;
|
||||
border: none;
|
||||
}
|
||||
img.inlineImg{
|
||||
display: inline-block;
|
||||
}
|
||||
textarea.fullWidth{
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
}
|
||||
table{
|
||||
width: 100%;
|
||||
}
|
||||
h1{
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<meta charset="UTF-8">
|
||||
<title>image2cpp</title>
|
||||
<style type="text/css">
|
||||
body{
|
||||
font-family: arial;
|
||||
}
|
||||
.wrapper{
|
||||
width: 800px;
|
||||
margin: auto;
|
||||
}
|
||||
.numberInput{
|
||||
width: 50px;
|
||||
}
|
||||
label{
|
||||
width: 220px;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
}
|
||||
label.smallLabel{
|
||||
width: auto;
|
||||
}
|
||||
td{
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
td.or{
|
||||
padding: 20px;
|
||||
width: 100px;
|
||||
font-size: 30px;
|
||||
/*vertical-align: center;*/
|
||||
}
|
||||
hr{
|
||||
height: 3px;
|
||||
background-color: black;
|
||||
border: none;
|
||||
}
|
||||
img.inlineImg{
|
||||
display: inline-block;
|
||||
}
|
||||
textarea.fullWidth{
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
}
|
||||
table{
|
||||
width: 100%;
|
||||
}
|
||||
h1{
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<h1>image2cpp</h1>
|
||||
<p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<h2>1. Select image</h2>
|
||||
<input type="file" id="fileInput" name="fileinput"/><br />
|
||||
<label>Selected image size:</label> <span id="imageSize">no image selected</span>
|
||||
</h4>
|
||||
<td class="or">or</td>
|
||||
<td>
|
||||
<h2>1. Paste byte array</h2>
|
||||
<textarea id="textInput" class="fullWidth"></textarea><br />
|
||||
<button onclick="handleTextInput('horizontal')">Read as horizontal</button>
|
||||
<button onclick="handleTextInput('vertical')">Read as vertical</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<hr />
|
||||
<div class="wrapper">
|
||||
<h1>image2cpp</h1>
|
||||
<p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<h2>1. Select image</h2>
|
||||
<input type="file" id="fileInput" name="fileinput"/><br />
|
||||
<label>Selected image size:</label> <span id="imageSize">no image selected</span>
|
||||
</h4>
|
||||
<td class="or">or</td>
|
||||
<td>
|
||||
<h2>1. Paste byte array</h2>
|
||||
<textarea id="textInput" class="fullWidth"></textarea><br />
|
||||
<button onclick="handleTextInput('horizontal')">Read as horizontal</button>
|
||||
<button onclick="handleTextInput('vertical')">Read as vertical</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
<h2>2. Image Settings</h2>
|
||||
<label>Canvas size: </label> <input id="screenWidth" class="numberInput" type="text" name="screenWidth" onchange="updateInteger('screenWidth')" value="128"/> * <input id="screenHeight" class="numberInput" type="text" name="screenHeight" onchange="updateInteger('screenHeight')" value="64"/> pixels<br />
|
||||
<label>Background color:</label>
|
||||
<input id="backgroundColorWhite" type="radio" name="backgroundColor" value="white" checked="checked" onchange="updateRadio('backgroundColor')"/><label for="backgroundColorWhite" class="smallLabel">White</label>
|
||||
<input id="backgroundColorBlack" type="radio" name="backgroundColor" value="black" onchange="updateRadio('backgroundColor')"/><label for="backgroundColorBlack" class="smallLabel">Black</label><br />
|
||||
<label>Brightness threshold: </label> <input id="threshold" class="numberInput" type="text" name="threshold" onchange="updateInteger('threshold')" value="128"/> <i>0 - 255; pixels with brightness above become white, below become black.</i><br/>
|
||||
<label for="scale">Scaling</label>
|
||||
<select id="scale" name="scale" onchange="updateInteger('scale')">
|
||||
<option value="1">original size</option>
|
||||
<option value="2">scale to fit, keeping proportions</option>
|
||||
<option value="3">stretch to fill canvas</option>
|
||||
<option value="4">stretch to fill canvas horizontally</option>
|
||||
<option value="5">stretch to fill canvas vertically</option>
|
||||
</select><br />
|
||||
<p>
|
||||
<h2>2. Image Settings</h2>
|
||||
<label>Canvas size: </label> <input id="screenWidth" class="numberInput" type="text" name="screenWidth" onchange="updateInteger('screenWidth')" value="128"/> * <input id="screenHeight" class="numberInput" type="text" name="screenHeight" onchange="updateInteger('screenHeight')" value="64"/> pixels<br />
|
||||
<label>Background color:</label>
|
||||
<input id="backgroundColorWhite" type="radio" name="backgroundColor" value="white" checked="checked" onchange="updateRadio('backgroundColor')"/><label for="backgroundColorWhite" class="smallLabel">White</label>
|
||||
<input id="backgroundColorBlack" type="radio" name="backgroundColor" value="black" onchange="updateRadio('backgroundColor')"/><label for="backgroundColorBlack" class="smallLabel">Black</label><br />
|
||||
<label>Brightness threshold: </label> <input id="threshold" class="numberInput" type="text" name="threshold" onchange="updateInteger('threshold')" value="128"/> <i>0 - 255; pixels with brightness above become white, below become black.</i><br/>
|
||||
<label for="scale">Scaling</label>
|
||||
<select id="scale" name="scale" onchange="updateInteger('scale')">
|
||||
<option value="1">original size</option>
|
||||
<option value="2">scale to fit, keeping proportions</option>
|
||||
<option value="3">stretch to fill canvas</option>
|
||||
<option value="4">stretch to fill canvas horizontally</option>
|
||||
<option value="5">stretch to fill canvas vertically</option>
|
||||
</select><br />
|
||||
|
||||
<label for="centerHorizontally">Center horizontally</label><input id="centerHorizontally" type="checkbox" onchange="updateBoolean('centerHorizontally')" /><br />
|
||||
<label for="centerVertically">Center vertically</label><input id="centerVertically" type="checkbox" onchange="updateBoolean('centerVertically')" /><br />
|
||||
<i>Centering the image only works when using a canvas larger than the selected image.</i><br />
|
||||
<label for="invertColors">Invert image colors</label><input id="invertColors" type="checkbox" onchange="updateBoolean('invertColors')" />
|
||||
</p>
|
||||
<label for="centerHorizontally">Center horizontally</label><input id="centerHorizontally" type="checkbox" onchange="updateBoolean('centerHorizontally')" /><br />
|
||||
<label for="centerVertically">Center vertically</label><input id="centerVertically" type="checkbox" onchange="updateBoolean('centerVertically')" /><br />
|
||||
<i>Centering the image only works when using a canvas larger than the selected image.</i><br />
|
||||
<label for="invertColors">Invert image colors</label><input id="invertColors" type="checkbox" onchange="updateBoolean('invertColors')" />
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
<h2>3. Preview</h2>
|
||||
<canvas id="imageCanvas" style="border: 1px solid black;" width="128" height="64"></canvas>
|
||||
</p>
|
||||
<p>
|
||||
<h2>3. Preview</h2>
|
||||
<canvas id="imageCanvas" style="border: 1px solid black;" width="128" height="64"></canvas>
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
<h2>4. Output</h2>
|
||||
<label for="addArduinoCode">Add Arduino code</label><input id="addArduinoCode" type="checkbox" onchange="updateBoolean('addArduinoCode')" /><br />
|
||||
<i>Adds some extra Arduino code around the output for easy copy-paste into <a href="https://github.com/javl/image2cpp/blob/master/oled_example/oled_example.ino" target="_blank">this example</a>.</i><br />
|
||||
<br />
|
||||
<label>Draw mode:</label>
|
||||
<input id="drawModeHorizontal" type="radio" name="drawMode" value="horizontal" checked="checked" onchange="updateRadio('drawMode')"/><label for="drawModeHorizontal" class="smallLabel">Horizontal</label>
|
||||
<input id="drawModeVertical" type="radio" name="drawMode" value="vertical" onchange="updateRadio('drawMode')"/><label for="drawModeVertical" class="smallLabel">Vertical</label><br />
|
||||
<i>If your image looks all messed up on your display, like the image below, try the other mode.</i><br />
|
||||
<br />
|
||||
<img class="inlineImg" src="img/error.jpg" width="150" height="64" alt="" /><br /><br />
|
||||
<button type="button" onclick="outputString()">Generate code</button><br /><br />
|
||||
<textarea id="outputField" class="fullWidth"></textarea>
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript" src="script.js"></script>
|
||||
<p>
|
||||
<h2>4. Output</h2>
|
||||
<label for="addArduinoCode">Add Arduino code</label><input id="addArduinoCode" type="checkbox" onchange="updateBoolean('addArduinoCode')" /><br />
|
||||
<i>Adds some extra Arduino code around the output for easy copy-paste into <a href="https://github.com/javl/image2cpp/blob/master/oled_example/oled_example.ino" target="_blank">this example</a>.</i><br />
|
||||
<br />
|
||||
<label>Draw mode:</label>
|
||||
<input id="drawModeHorizontal" type="radio" name="drawMode" value="horizontal" checked="checked" onchange="updateRadio('drawMode')"/><label for="drawModeHorizontal" class="smallLabel">Horizontal</label>
|
||||
<input id="drawModeVertical" type="radio" name="drawMode" value="vertical" onchange="updateRadio('drawMode')"/><label for="drawModeVertical" class="smallLabel">Vertical</label><br />
|
||||
<i>If your image looks all messed up on your display, like the image below, try the other mode.</i><br />
|
||||
<br />
|
||||
<img class="inlineImg" src="img/error.jpg" width="150" height="64" alt="" /><br /><br />
|
||||
<button type="button" onclick="outputString()">Generate code</button><br /><br />
|
||||
<textarea id="outputField" class="fullWidth"></textarea>
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/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);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*********************************************************************
|
||||
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 <SPI.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
|
||||
#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() {
|
||||
// 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:
|
||||
// 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() {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user