mirror of
https://github.com/lospec/pixel-editor.git
synced 2023-08-10 21:12:51 +03:00
Finished implementing project loading and saving
This commit is contained in:
@ -17,6 +17,7 @@ Suggestions / Planned features:
|
|||||||
- Snap brush preview to pixel grid
|
- Snap brush preview to pixel grid
|
||||||
- Move selection with arrows
|
- Move selection with arrows
|
||||||
- Load palette from LPE file
|
- Load palette from LPE file
|
||||||
|
- Move colours in palette editor
|
||||||
|
|
||||||
- Custom color picker
|
- Custom color picker
|
||||||
- custom code without dependencies
|
- custom code without dependencies
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
|
||||||
function createColorPalette(selectedPalette, fillBackground) {
|
function createColorPalette(selectedPalette, fillBackground, deletePreviousPalette = true) {
|
||||||
//remove current palette
|
//remove current palette
|
||||||
colors = document.getElementsByClassName('color-button');
|
if (deletePreviousPalette) {
|
||||||
while (colors.length > 0) {
|
colors = document.getElementsByClassName('color-button');
|
||||||
colors[0].parentElement.remove();
|
while (colors.length > 0) {
|
||||||
|
colors[0].parentElement.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var lightestColor = '#000000';
|
var lightestColor = '#000000';
|
||||||
@ -31,9 +33,49 @@ function createColorPalette(selectedPalette, fillBackground) {
|
|||||||
|
|
||||||
darkestColor = newColor;
|
darkestColor = newColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//set as current color
|
//set as current color
|
||||||
currentLayer.context.fillStyle = darkestColor;
|
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);
|
||||||
|
}
|
@ -202,22 +202,27 @@ function closeMenu () {
|
|||||||
|
|
||||||
function getProjectData() {
|
function getProjectData() {
|
||||||
// use a dictionary
|
// 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
|
// store canvas size
|
||||||
dictionary.push({key: "canvasWidth", value: currentLayer.canvasSize[0]});
|
dictionary['canvasWidth'] = currentLayer.canvasSize[0];
|
||||||
dictionary.push({key: "canvasHeight", value: currentLayer.canvasSize[1]});
|
dictionary['canvasHeight'] = currentLayer.canvasSize[1];
|
||||||
// store palette
|
// store palette
|
||||||
for (let i=0; i<currentPalette.length; i++) {
|
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
|
// 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)
|
// Only saving the layers the user has access to (no vfx, tmp or checkerboard layers)
|
||||||
if (layers[i].menuEntry != null) {
|
if (layersCopy[i].menuEntry != null) {
|
||||||
dictionary.push({key: "layer" + i, value: layers[i]});
|
dictionary["layer" + i] = layersCopy[i];
|
||||||
dictionary.push({key: "layer" + i + "ImageData",
|
dictionary["layer" + i + "ImageData"] = layersCopy[i].canvas.toDataURL();
|
||||||
value: layers[i].canvas.toDataURL()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,6 @@ class Layer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
layerDragStart(element) {
|
layerDragStart(element) {
|
||||||
layerList.children[layerList.childElementCount - 2].setAttribute("draggable", "true");
|
|
||||||
layerDragSource = this;
|
layerDragSource = this;
|
||||||
element.dataTransfer.effectAllowed = 'move';
|
element.dataTransfer.effectAllowed = 'move';
|
||||||
element.dataTransfer.setData('text/html', this.id);
|
element.dataTransfer.setData('text/html', this.id);
|
||||||
@ -151,7 +150,6 @@ class Layer {
|
|||||||
|
|
||||||
layerDragEnd(element) {
|
layerDragEnd(element) {
|
||||||
this.classList.remove('layerdragover');
|
this.classList.remove('layerdragover');
|
||||||
layerList.children[layerList.childElementCount - 2].setAttribute("draggable", "false");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resizes canvas
|
// Resizes canvas
|
||||||
@ -452,7 +450,7 @@ function renameLayer(event) {
|
|||||||
function moveLayers(toDropLayer, staticLayer, saveHistory = true) {
|
function moveLayers(toDropLayer, staticLayer, saveHistory = true) {
|
||||||
let toDrop = getLayerByID(toDropLayer);
|
let toDrop = getLayerByID(toDropLayer);
|
||||||
let static = getLayerByID(staticLayer);
|
let static = getLayerByID(staticLayer);
|
||||||
let layerCopy = layers;
|
let layerCopy = layers.slice();
|
||||||
|
|
||||||
let beforeToDrop = toDrop.menuEntry.nextElementSibling;
|
let beforeToDrop = toDrop.menuEntry.nextElementSibling;
|
||||||
let nMoved = 0;
|
let nMoved = 0;
|
||||||
@ -547,6 +545,7 @@ function getLayerByID(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addLayer(id, saveHistory = true) {
|
function addLayer(id, saveHistory = true) {
|
||||||
|
// layers.length - 3
|
||||||
let index = layers.length - 3;
|
let index = layers.length - 3;
|
||||||
// Creating a new canvas
|
// Creating a new canvas
|
||||||
let newCanvas = document.createElement("canvas");
|
let newCanvas = document.createElement("canvas");
|
||||||
@ -583,4 +582,6 @@ function addLayer(id, saveHistory = true) {
|
|||||||
if (saveHistory) {
|
if (saveHistory) {
|
||||||
new HistoryStateAddLayer(newLayer, index);
|
new HistoryStateAddLayer(newLayer, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return newLayer;
|
||||||
}
|
}
|
@ -1,13 +1,19 @@
|
|||||||
document.getElementById('open-image-browse-holder').addEventListener('change', function () {
|
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 (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
|
reader.readAsText(file, "UTF-8");
|
||||||
var fileContentType = this.files[0].type;
|
reader.onload = function (e) {
|
||||||
console.log("File: " + fileContentType);
|
let dictionary = JSON.parse(e.target.result);
|
||||||
|
|
||||||
if (fileContentType == 'image/png' || fileContentType == 'image/gif' || fileContentType == '.lpe') {
|
newPixel(dictionary['canvasWidth'], dictionary['canvasHeight'], [], dictionary);
|
||||||
if (fileContentType == '.lpe') {
|
}
|
||||||
console.log("OK");
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//load file
|
//load file
|
||||||
@ -15,43 +21,12 @@ document.getElementById('open-image-browse-holder').addEventListener('change', f
|
|||||||
fileReader.onload = function(e) {
|
fileReader.onload = function(e) {
|
||||||
var img = new Image();
|
var img = new Image();
|
||||||
img.onload = function() {
|
img.onload = function() {
|
||||||
|
|
||||||
//create a new pixel with the images dimentions
|
//create a new pixel with the images dimentions
|
||||||
newPixel(this.width, this.height, []);
|
newPixel(this.width, this.height, []);
|
||||||
|
|
||||||
//draw the image onto the canvas
|
//draw the image onto the canvas
|
||||||
currentLayer.context.drawImage(img, 0, 0);
|
currentLayer.context.drawImage(img, 0, 0);
|
||||||
|
createPaletteFromLayers();
|
||||||
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);
|
|
||||||
|
|
||||||
//track google event
|
//track google event
|
||||||
ga('send', 'event', 'Pixel Editor Load', colorPalette.length, this.width+'/'+this.height); /*global ga*/
|
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.');
|
else alert('Only .lpe project files, PNG and GIF files are allowed at this time.');
|
||||||
}
|
}
|
||||||
});
|
});
|
@ -1,6 +1,6 @@
|
|||||||
let firstPixel = true;
|
let firstPixel = true;
|
||||||
|
|
||||||
function newPixel (width, height, palette) {
|
function newPixel (width, height, palette, fileContent = null) {
|
||||||
currentPalette = [];
|
currentPalette = [];
|
||||||
if (firstPixel) {
|
if (firstPixel) {
|
||||||
layerList = document.getElementById("layers-menu");
|
layerList = document.getElementById("layers-menu");
|
||||||
@ -74,7 +74,7 @@ function newPixel (width, height, palette) {
|
|||||||
|
|
||||||
//add colors from selected palette
|
//add colors from selected palette
|
||||||
var selectedPalette = getText('palette-button');
|
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 this palette isnt the one specified in the url, then reset the url
|
||||||
if (!palettes[selectedPalette].specified)
|
if (!palettes[selectedPalette].specified)
|
||||||
@ -82,26 +82,22 @@ function newPixel (width, height, palette) {
|
|||||||
|
|
||||||
//fill the palette with specified palette
|
//fill the palette with specified palette
|
||||||
createColorPalette(palettes[selectedPalette].colors,true);
|
createColorPalette(palettes[selectedPalette].colors,true);
|
||||||
fillCheckerboard();
|
|
||||||
}
|
}
|
||||||
else {
|
else if (fileContent == null) {
|
||||||
//this wasn't a specified palette, so reset the url
|
//this wasn't a specified palette, so reset the url
|
||||||
history.pushState(null, null, '/pixel-editor/app');
|
history.pushState(null, null, '/pixel-editor/app');
|
||||||
|
|
||||||
//generate default colors
|
//generate default colors
|
||||||
var fg = hslToRgb(Math.floor(Math.random()*255), 230,70);
|
var fg = hslToRgb(Math.floor(Math.random()*255), 230,70);
|
||||||
var bg = hslToRgb(Math.floor(Math.random()*255), 230,170);
|
var bg = hslToRgb(Math.floor(Math.random()*255), 230,170);
|
||||||
|
|
||||||
//convert colors to hex
|
//convert colors to hex
|
||||||
var defaultForegroundColor = rgbToHex(fg.r,fg.g,fg.b);
|
var defaultForegroundColor = rgbToHex(fg.r,fg.g,fg.b);
|
||||||
var defaultBackgroundColor = rgbToHex(bg.r,bg.g,bg.b);
|
var defaultBackgroundColor = rgbToHex(bg.r,bg.g,bg.b);
|
||||||
|
|
||||||
//add colors to paletee
|
//add colors to palette
|
||||||
addColor(defaultForegroundColor).classList.add('selected');
|
addColor(defaultForegroundColor).classList.add('selected');
|
||||||
addColor(defaultBackgroundColor);
|
addColor(defaultBackgroundColor);
|
||||||
|
|
||||||
//fill background of canvas with bg color
|
|
||||||
fillCheckerboard();
|
|
||||||
|
|
||||||
//set current drawing color as foreground color
|
//set current drawing color as foreground color
|
||||||
currentLayer.context.fillStyle = '#'+defaultForegroundColor;
|
currentLayer.context.fillStyle = '#'+defaultForegroundColor;
|
||||||
@ -109,6 +105,9 @@ function newPixel (width, height, palette) {
|
|||||||
selectedPalette = 'none';
|
selectedPalette = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fill background of canvas with bg color
|
||||||
|
fillCheckerboard();
|
||||||
|
|
||||||
//reset undo and redo states
|
//reset undo and redo states
|
||||||
undoStates = [];
|
undoStates = [];
|
||||||
redoStates = [];
|
redoStates = [];
|
||||||
@ -120,4 +119,43 @@ function newPixel (width, height, palette) {
|
|||||||
documentCreated = true;
|
documentCreated = true;
|
||||||
|
|
||||||
firstPixel = false;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user