diff --git a/js/ColorModule.js b/js/ColorModule.js index c791bc5..44974e3 100644 --- a/js/ColorModule.js +++ b/js/ColorModule.js @@ -388,10 +388,12 @@ const ColorModule = (() => { * * @param {*} paletteColors The colours of the palette */ - function createColorPalette(paletteColors) { + function createColorPalette(paletteColors, clearCurrent=true) { //remove current palette - while (colorsMenu.childElementCount > 1) - colorsMenu.children[0].remove(); + if (clearCurrent) { + while (colorsMenu.childElementCount > 1) + colorsMenu.children[0].remove(); + } var lightestColor = new Color("hex", '#000000'); var darkestColor = new Color("hex", '#ffffff'); @@ -527,4 +529,4 @@ const ColorModule = (() => { updateCurrentColor, getSelectedColor, } -})(); \ No newline at end of file +})(); diff --git a/js/FileManager.js b/js/FileManager.js index fcae2b5..730181d 100644 --- a/js/FileManager.js +++ b/js/FileManager.js @@ -292,57 +292,143 @@ const FileManager = (() => { return JSON.stringify(dictionary); } + + let fromMenu = false; + + function openImportPaletteWindow() { + fromMenu = true; + document.getElementById('load-palette-browse-holder').click(); + } + function loadPalette() { if (browsePaletteHolder.files && browsePaletteHolder.files[0]) { - //make sure file is allowed filetype - var fileContentType = browsePaletteHolder.files[0].type; - if (fileContentType == 'image/png' || fileContentType == 'image/gif') { + let file = browsePaletteHolder.files[0]; + var fileContentType = + file.type + || file.name.split('.').slice(-1)[0]; - //load file - var fileReader = new FileReader(); - fileReader.onload = function(e) { - var img = new Image(); - img.onload = function() { - - //draw image onto the temporary canvas - var loadPaletteCanvas = document.getElementById('load-palette-canvas-holder'); - var loadPaletteContext = loadPaletteCanvas.getContext('2d'); - - loadPaletteCanvas.width = img.width; - loadPaletteCanvas.height = img.height; - - loadPaletteContext.drawImage(img, 0, 0); - - //create array to hold found colors - var colorPalette = []; - var imagePixelData = loadPaletteContext.getImageData(0,0,this.width, this.height).data; - - //loop through pixels looking for colors to add to palette - for (var i = 0; i < imagePixelData.length; i += 4) { - const newColor = {r:imagePixelData[i],g:imagePixelData[i + 1],b:imagePixelData[i + 2]}; - var color = '#' + Color.rgbToHex(newColor); - if (colorPalette.indexOf(color) == -1) { - colorPalette.push(color); - } - } - - //add to palettes so that it can be loaded when they click okay - palettes['Loaded palette'] = {}; - palettes['Loaded palette'].colors = colorPalette; - Util.setText('palette-button', 'Loaded palette'); - Util.setText('palette-button-splash', 'Loaded palette'); - Util.toggle('palette-menu-splash'); - }; - img.src = e.target.result; - }; + var fileReader = new FileReader(); + + // dispatch on file type + switch (fileContentType) { + case 'image/png': + case 'image/gif': + fileReader.onload = loadPaletteFromImage; fileReader.readAsDataURL(browsePaletteHolder.files[0]); + break; + case 'gpl': + fileReader.onload = loadPaletteFromGimp; + fileReader.readAsText(browsePaletteHolder.files[0]); + break; + case 'hex': + fileReader.onload = loadPaletteFromHex; + fileReader.readAsText(browsePaletteHolder.files[0]); + break; + default: + alert('Only PNG, GIF, .hex and .gpl files are supported at this time.'); } - else alert('Only PNG and GIF files are supported at this time.'); } browsePaletteHolder.value = null; } + function addPalette(colors) { + if (fromMenu) { + ColorModule.createColorPalette(colors, clearCurrent=false); + } else { + // From splash screen + // add to palettes so that it can be loaded when they click okay + palettes['Loaded palette'] = {}; + palettes['Loaded palette'].colors = colors; + Util.setText('palette-button', 'Loaded palette'); + Util.setText('palette-button-splash', 'Loaded palette'); + Util.toggle('palette-menu-splash'); + } + } + + function loadPaletteFromImage(e) { + var img = new Image(); + img.onload = function() { + //draw image onto the temporary canvas + var loadPaletteCanvas = document.getElementById('load-palette-canvas-holder'); + var loadPaletteContext = loadPaletteCanvas.getContext('2d'); + + loadPaletteCanvas.width = img.width; + loadPaletteCanvas.height = img.height; + + loadPaletteContext.drawImage(img, 0, 0); + + //create array to hold found colors + var colorPalette = []; + var imagePixelData = loadPaletteContext.getImageData(0,0,this.width, this.height).data; + + //loop through pixels looking for colors to add to palette + for (var i = 0; i < imagePixelData.length; i += 4) { + const newColor = {r:imagePixelData[i],g:imagePixelData[i + 1],b:imagePixelData[i + 2]}; + var color = '#' + Color.rgbToHex(newColor); + if (colorPalette.indexOf(color) == -1) { + colorPalette.push(color); + } + } + + addPalette(colorPalette); + }; + img.src = e.target.result; + } + + function loadPaletteFromGimp(e) { + let content = e.target.result; + let colorPalette = content.split(/\r?\n/) + // Skip header line + .slice(1) + .map((line) => line.trim()) + .filter((line) => line != "") + // discard comment lines + .filter((line) => !line.startsWith('#')) + // discard meta data lines + .filter((line) => !line.includes(':')) + .map((line) => { + let components = line.split(/\s+/); + + if (components.length < 3) { + alert(`Invalid color specification ${line}.`); + return "#000000" + } + + let [r, g, b, ...rest] = components; + let color = { + r: parseInt(r), + g: parseInt(g), + b: parseInt(b), + }; + + if (isNaN(color.r) || isNaN(color.g) || isNaN(color.b)) { + alert(`Invalid color specification ${line}.`); + return "#000000" + } + + return '#' + Color.rgbToHex(color); + }); + addPalette(colorPalette); + } + + function loadPaletteFromHex(e) { + let content = e.target.result; + let colorPalette = content.split(/\r?\n/) + .map((line) => line.trim()) + .filter((line) => line != "") + // discard comment lines + .filter((line) => !line.startsWith('#')) + .map((line) => { + if (line.match(/[0-9A-Fa-f]{6}/)) { + return '#' + line; + } + alert(`Invalid hex color ${line}.`); + return '#000000'; + }); + addPalette(colorPalette); + } + currentImportPivotElement = undefined; currentImportPivotPosition = 'middle'; isImportWindowInitialized = false; @@ -513,6 +599,7 @@ const FileManager = (() => { openPixelExportWindow, openSaveProjectWindow, openImportImageWindow, + openImportPaletteWindow, open } @@ -526,4 +613,4 @@ const FileManager = (() => { } }) return ret; -})(); \ No newline at end of file +})(); diff --git a/js/TopMenuModule.js b/js/TopMenuModule.js index 6b88ede..6dfa558 100644 --- a/js/TopMenuModule.js +++ b/js/TopMenuModule.js @@ -46,6 +46,9 @@ const TopMenuModule = (() => { case 'Import': Events.on('click', currSubmenuButton, FileManager.openImportImageWindow); break; + case 'Load palette': + Events.on('click', currSubmenuButton, FileManager.openImportPaletteWindow); + break; case 'Export': Events.on('click', currSubmenuButton, FileManager.openPixelExportWindow); break; @@ -139,4 +142,4 @@ const TopMenuModule = (() => { addInfoElement, resetInfos } -})(); \ No newline at end of file +})(); diff --git a/views/holders.hbs b/views/holders.hbs index a144583..054aaad 100644 --- a/views/holders.hbs +++ b/views/holders.hbs @@ -2,7 +2,7 @@ dl dl - + - \ No newline at end of file + diff --git a/views/main-menu.hbs b/views/main-menu.hbs index 2b43857..059037f 100644 --- a/views/main-menu.hbs +++ b/views/main-menu.hbs @@ -7,6 +7,7 @@
  • +
  • Exit
  • @@ -74,4 +75,4 @@
  • {{> checkbox}}
  • - \ No newline at end of file +