Finished implementing project loading and saving

This commit is contained in:
unsettledgames 2020-06-28 16:57:19 +02:00
parent 2868363bb7
commit caa81dde1c
6 changed files with 137 additions and 75 deletions

View File

@ -17,6 +17,7 @@ Suggestions / Planned features:
- Snap brush preview to pixel grid
- Move selection with arrows
- Load palette from LPE file
- Move colours in palette editor
- Custom color picker
- custom code without dependencies

View File

@ -1,9 +1,11 @@
function createColorPalette(selectedPalette, fillBackground) {
function createColorPalette(selectedPalette, fillBackground, deletePreviousPalette = true) {
//remove current palette
colors = document.getElementsByClassName('color-button');
while (colors.length > 0) {
colors[0].parentElement.remove();
if (deletePreviousPalette) {
colors = document.getElementsByClassName('color-button');
while (colors.length > 0) {
colors[0].parentElement.remove();
}
}
var lightestColor = '#000000';
@ -31,9 +33,49 @@ function createColorPalette(selectedPalette, fillBackground) {
darkestColor = newColor;
}
}
//set as current color
currentLayer.context.fillStyle = darkestColor;
}
function createPaletteFromLayers() {
let colors = {};
for (let i=0; i<layers.length; i++) {
if (layers[i].menuEntry != null) {
let imageData = layers[i].context.getImageData(0, 0, layers[i].canvasSize[0], layers[i].canvasSize[1]).data;
let dataLength = imageData.length;
for (let j=0; j<dataLength; j += 4) {
if (!isPixelEmpty(imageData[j])) {
let color = imageData[j]+','+imageData[j + 1]+','+imageData[j + 2];
if (!colors[color]) {
colors[color] = {r:imageData[j],g:imageData[j + 1],b:imageData[j + 2]};
//don't allow more than 256 colors to be added
if (Object.keys(colors).length >= settings.maxColorsOnImportedImage) {
alert('The image loaded seems to have more than '+settings.maxColorsOnImportedImage+' colors.');
break;
}
}
}
}
}
}
console.log(colors);
//create array out of colors object
let colorPaletteArray = [];
for (let color in colors) {
if (colors.hasOwnProperty(color)) {
colorPaletteArray.push('#'+rgbToHex(colors[color]));
}
}
console.log('COLOR PALETTE ARRAY', colorPaletteArray);
//create palette form colors array
createColorPalette(colorPaletteArray, false);
}

View File

@ -202,22 +202,27 @@ function closeMenu () {
function getProjectData() {
// use a dictionary
let dictionary = [];
let dictionary = {};
// sorting layers by increasing z-index
let layersCopy = layers.slice();
layersCopy.sort((a, b) => (a.canvas.style.zIndex > b.canvas.style.zIndex) ? 1 : -1);
// store canvas size
dictionary.push({key: "canvasWidth", value: currentLayer.canvasSize[0]});
dictionary.push({key: "canvasHeight", value: currentLayer.canvasSize[1]});
dictionary['canvasWidth'] = currentLayer.canvasSize[0];
dictionary['canvasHeight'] = currentLayer.canvasSize[1];
// store palette
for (let i=0; i<currentPalette.length; i++) {
dictionary.push({key: "color" + i, value: currentPalette[i]});
dictionary["color" + i] = currentPalette[i];
}
// Store number of layers
dictionary["nLayers"] = layersCopy.length;
// store layers
for (let i=0; i<layers.length; i++) {
for (let i=0; i<layersCopy.length; i++) {
// Only saving the layers the user has access to (no vfx, tmp or checkerboard layers)
if (layers[i].menuEntry != null) {
dictionary.push({key: "layer" + i, value: layers[i]});
dictionary.push({key: "layer" + i + "ImageData",
value: layers[i].canvas.toDataURL()
});
if (layersCopy[i].menuEntry != null) {
dictionary["layer" + i] = layersCopy[i];
dictionary["layer" + i + "ImageData"] = layersCopy[i].canvas.toDataURL();
}
}

View File

@ -107,7 +107,6 @@ class Layer {
}
layerDragStart(element) {
layerList.children[layerList.childElementCount - 2].setAttribute("draggable", "true");
layerDragSource = this;
element.dataTransfer.effectAllowed = 'move';
element.dataTransfer.setData('text/html', this.id);
@ -151,7 +150,6 @@ class Layer {
layerDragEnd(element) {
this.classList.remove('layerdragover');
layerList.children[layerList.childElementCount - 2].setAttribute("draggable", "false");
}
// Resizes canvas
@ -452,7 +450,7 @@ function renameLayer(event) {
function moveLayers(toDropLayer, staticLayer, saveHistory = true) {
let toDrop = getLayerByID(toDropLayer);
let static = getLayerByID(staticLayer);
let layerCopy = layers;
let layerCopy = layers.slice();
let beforeToDrop = toDrop.menuEntry.nextElementSibling;
let nMoved = 0;
@ -547,6 +545,7 @@ function getLayerByID(id) {
}
function addLayer(id, saveHistory = true) {
// layers.length - 3
let index = layers.length - 3;
// Creating a new canvas
let newCanvas = document.createElement("canvas");
@ -583,4 +582,6 @@ function addLayer(id, saveHistory = true) {
if (saveHistory) {
new HistoryStateAddLayer(newLayer, index);
}
return newLayer;
}

View File

@ -1,13 +1,19 @@
document.getElementById('open-image-browse-holder').addEventListener('change', function () {
let fileName = document.getElementById("open-image-browse-holder").value;
let extension = fileName.substring(fileName.lastIndexOf('.')+1, fileName.length) || fileName;
if (this.files && this.files[0]) {
if (extension == 'png' || extension == 'gif' || extension == 'lpe') {
if (extension == 'lpe') {
let file = this.files[0];
let reader = new FileReader();
//make sure file is allowed filetype
var fileContentType = this.files[0].type;
console.log("File: " + fileContentType);
reader.readAsText(file, "UTF-8");
reader.onload = function (e) {
let dictionary = JSON.parse(e.target.result);
if (fileContentType == 'image/png' || fileContentType == 'image/gif' || fileContentType == '.lpe') {
if (fileContentType == '.lpe') {
console.log("OK");
newPixel(dictionary['canvasWidth'], dictionary['canvasHeight'], [], dictionary);
}
}
else {
//load file
@ -15,43 +21,12 @@ document.getElementById('open-image-browse-holder').addEventListener('change', f
fileReader.onload = function(e) {
var img = new Image();
img.onload = function() {
//create a new pixel with the images dimentions
newPixel(this.width, this.height, []);
//draw the image onto the canvas
currentLayer.context.drawImage(img, 0, 0);
var colorPalette = {};
var imagePixelData = currentLayer.context.getImageData(0,0,this.width, this.height).data;
var imagePixelDataLength = imagePixelData.length;
console.log(imagePixelData);
for (var i = 0; i < imagePixelDataLength; i += 4) {
var color = imagePixelData[i]+','+imagePixelData[i + 1]+','+imagePixelData[i + 2];
if (!colorPalette[color]) {
colorPalette[color] = {r:imagePixelData[i],g:imagePixelData[i + 1],b:imagePixelData[i + 2]};
//don't allow more than 256 colors to be added
if (Object.keys(colorPalette).length >= settings.maxColorsOnImportedImage) {
alert('The image loaded seems to have more than '+settings.maxColorsOnImportedImage+' colors.');
break;
}
}
}
//create array out of colors object
var colorPaletteArray = [];
for (var color in colorPalette) {
if( colorPalette.hasOwnProperty(color) ) {
colorPaletteArray.push('#'+rgbToHex(colorPalette[color]));
}
}
console.log('COLOR PALETTE ARRAY', colorPaletteArray);
//create palette form colors array
createColorPalette(colorPaletteArray, false);
createPaletteFromLayers();
//track google event
ga('send', 'event', 'Pixel Editor Load', colorPalette.length, this.width+'/'+this.height); /*global ga*/
@ -64,4 +39,4 @@ document.getElementById('open-image-browse-holder').addEventListener('change', f
}
else alert('Only .lpe project files, PNG and GIF files are allowed at this time.');
}
});
});

View File

@ -1,6 +1,6 @@
let firstPixel = true;
function newPixel (width, height, palette) {
function newPixel (width, height, palette, fileContent = null) {
currentPalette = [];
if (firstPixel) {
layerList = document.getElementById("layers-menu");
@ -74,7 +74,7 @@ function newPixel (width, height, palette) {
//add colors from selected palette
var selectedPalette = getText('palette-button');
if (selectedPalette != 'Choose a palette...') {
if (selectedPalette != 'Choose a palette...' && fileContent == null) {
//if this palette isnt the one specified in the url, then reset the url
if (!palettes[selectedPalette].specified)
@ -82,26 +82,22 @@ function newPixel (width, height, palette) {
//fill the palette with specified palette
createColorPalette(palettes[selectedPalette].colors,true);
fillCheckerboard();
}
else {
//this wasn't a specified palette, so reset the url
history.pushState(null, null, '/pixel-editor/app');
else if (fileContent == null) {
//this wasn't a specified palette, so reset the url
history.pushState(null, null, '/pixel-editor/app');
//generate default colors
var fg = hslToRgb(Math.floor(Math.random()*255), 230,70);
var bg = hslToRgb(Math.floor(Math.random()*255), 230,170);
//generate default colors
var fg = hslToRgb(Math.floor(Math.random()*255), 230,70);
var bg = hslToRgb(Math.floor(Math.random()*255), 230,170);
//convert colors to hex
var defaultForegroundColor = rgbToHex(fg.r,fg.g,fg.b);
var defaultBackgroundColor = rgbToHex(bg.r,bg.g,bg.b);
//convert colors to hex
var defaultForegroundColor = rgbToHex(fg.r,fg.g,fg.b);
var defaultBackgroundColor = rgbToHex(bg.r,bg.g,bg.b);
//add colors to paletee
addColor(defaultForegroundColor).classList.add('selected');
addColor(defaultBackgroundColor);
//fill background of canvas with bg color
fillCheckerboard();
//add colors to palette
addColor(defaultForegroundColor).classList.add('selected');
addColor(defaultBackgroundColor);
//set current drawing color as foreground color
currentLayer.context.fillStyle = '#'+defaultForegroundColor;
@ -109,6 +105,9 @@ function newPixel (width, height, palette) {
selectedPalette = 'none';
}
//fill background of canvas with bg color
fillCheckerboard();
//reset undo and redo states
undoStates = [];
redoStates = [];
@ -120,4 +119,43 @@ function newPixel (width, height, palette) {
documentCreated = true;
firstPixel = false;
if (fileContent != null) {
console.log(fileContent);
for (let i=0; i<fileContent['nLayers']; i++) {
let layerData = fileContent['layer' + i];
let layerImage = fileContent['layer' + i + 'ImageData'];
if (layerData != null) {
// Setting id
let createdLayer = addLayer(layerData.id, false);
// Setting name
createdLayer.menuEntry.getElementsByTagName("p")[0].innerHTML = layerData.name;
// Adding the image (I can do that because they're sorted by increasing z-index)
let img = new Image();
img.onload = function() {
createdLayer.context.drawImage(img, 0, 0);
createdLayer.updateLayerPreview();
if (i == (fileContent['nLayers'] - 1)) {
createPaletteFromLayers();
}
};
img.src = layerImage;
// Setting visibility and lock options
if (!layerData.isVisible) {
createdLayer.hide();
}
if (layerData.isLocked) {
createdLayer.lock();
}
}
}
// Deleting the default layer
deleteLayer(false);
}
}