From 6416c26dedbaf56525de34c1f3c600b23bed3485 Mon Sep 17 00:00:00 2001 From: alpadev Date: Tue, 1 Apr 2014 01:26:03 +0200 Subject: [PATCH 1/6] Rewrote most of it.. to accomplish #52 (also the old code been a lil dirty imo :)) Returns now a "meta" field instead of two - height and maxheight - fields. The meta object contains these fields: ``` { maxHeight: int, maxWidth: int, images: [{ height: int, offsetY: int, totalHeight: int, width: int },...] } ``` --- lib/phantomspriter.js | 72 ++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/lib/phantomspriter.js b/lib/phantomspriter.js index 413e1c3..8179dcd 100644 --- a/lib/phantomspriter.js +++ b/lib/phantomspriter.js @@ -17,35 +17,51 @@ page.onConsoleMessage = function (msg) { page.evaluate(function () { var testdraw = function () { - var maxwidth = 0; - var maxheight = 0; - var allHeight = 0; - var heights = []; - var canvas = null; - - for (var i = 0; i < document.images.length; i++) { - maxheight += document.images[i].height; - if (maxwidth < document.images[i].width) { - maxwidth = document.images[i].width; - } - } - maxheight = maxheight + (document.images.length * parseInt(document.getElementById('test').getAttribute('rel'), 10)); - // Create canvas element - canvas = document.getElementById('test'); - canvas.setAttribute('width', maxwidth); - canvas.setAttribute('height', maxheight); - // Loop through all images - for (var j = 0; j < document.images.length; j++) { - // Insert before the image - var ctx = canvas.getContext('2d'); - - // Draw image to canvas - var beforeHeight = (j - 1 === -1) ? 0 : document.images[j - 1].height; - allHeight += (beforeHeight + parseInt(canvas.getAttribute('rel'), 10)); - heights.push(allHeight); - ctx.drawImage(document.images[j], 0, allHeight); + var images = document.images, + canvas = document.getElementById('test'), + ctx = canvas.getContext('2d'), + spriteCache = document.createElement('canvas'), + cacheCtx = spriteCache.getContext('2d'), + imgHeight = 0, + imgWidth = 0, + imgTotalHeight = 0, + spriteHeight = 0, + spriteWidth = 0, + spacing = parseInt(canvas.getAttribute('rel'), 10) || 0, + meta = { images: [] }; + + // loop all images + for (var i = 0, l = images.length; i < l; i += 1) { + imgHeight = images[i].height; + imgWidth = images[i].width; + imgTotalHeight = imgHeight + (i === l - 1 ? 0 : spacing); + + spriteHeight += imgTotalHeight; + spriteWidth = spriteWidth < imgWidth ? imgWidth : spriteWidth; + + // paint to cache + spriteCache.setAttribute('height', spriteHeight); + spriteCache.setAttribute('width', spriteWidth); + cacheCtx.drawImage(canvas, 0, 0); + + // draw the real canvas + canvas.setAttribute('height', spriteHeight); + canvas.setAttribute('width', spriteWidth); + ctx.drawImage(spriteCache, 0, 0); + ctx.drawImage(images[i], 0, spriteHeight - imgTotalHeight); + + meta.images.push({ + height: imgHeight, + width: imgWidth, + totalHeight: imgTotalHeight, + offsetY: spriteHeight - imgTotalHeight + }); } - return JSON.stringify({image: canvas.toDataURL(), heights: heights, maxheight: maxheight}) + '<<< Date: Tue, 1 Apr 2014 01:31:14 +0200 Subject: [PATCH 2/6] Updates the generator functions to adopt the changes introduced to the spriter script. See #52 Also did some cleanup to the output string building. --- tasks/sprites.js | 53 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/tasks/sprites.js b/tasks/sprites.js index d83dbe1..3404b9e 100644 --- a/tasks/sprites.js +++ b/tasks/sprites.js @@ -66,19 +66,31 @@ module.exports = function(grunt) { }); fileContents += imageClasses + ' {' + '\n' + ' background: url("' + generateBackgroundImagePath() + '") no-repeat;\n' + '}\n\n'; - imageData.heights.forEach(function (height, idx) { - fileContents += '.' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + ' {\n' + ' background-position: 0 ' + -height + ( height === 0 ? "" : 'px') + ';\n' + '}\n\n'; + imageData.images.forEach(function (meta, idx) { + fileContents += '.' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + + ' {\n' + + ' width: ' + intToPixel(meta.width) + ';\n' + + ' height: ' + intToPixel(meta.height) + ';\n' + + ' background-position: 0 ' + intToPixel(-meta.offsetY) + ';\n' + + '}\n\n'; }); return fileContents; } function generateSASSFile (imageData, images, placeholder, scssSyntax) { - var fileContents = ''; + var fileContents = '', + colon = (scssSyntax ? ';' : '') + '\n'; fileContents += "%" + placeholder + (scssSyntax ? ' {' : '') + '\n' + ' background: url("' + generateBackgroundImagePath() + '") no-repeat' + (scssSyntax ? ';\n }' : '') + '\n\n'; - imageData.heights.forEach(function (height, idx) { - fileContents += '%' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + (scssSyntax ? ' {' : '') + '\n @extend ' + '%' + placeholder + (scssSyntax ? ' ;' : '') + '\n' + ' background-position: 0 ' + -height + ( height === 0 ? "" : 'px') + (scssSyntax ? ';\n }' : '') + '\n\n'; + imageData.images.forEach(function (meta, idx) { + fileContents += '%' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + + (scssSyntax ? ' {' : '') + '\n' + + ' @extend ' + '%' + placeholder + colon + + ' width: ' + intToPixel(meta.width) + colon + + ' height: ' + intToPixel(meta.height) + colon + + ' background-position: 0 ' + intToPixel(-meta.offsetY) + colon + + (scssSyntax ? '}' : '') + '\n\n'; }); return fileContents; @@ -89,8 +101,13 @@ module.exports = function(grunt) { var fileContents = ''; fileContents += "." + placeholder + ' {\n' + ' background: url("' + generateBackgroundImagePath() + '") no-repeat;\n }' + '\n\n'; - imageData.heights.forEach(function (height, idx) { - fileContents += '.' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + ':extend(.' + placeholder + ') {\n' + ' background-position: 0 ' + -height + ( height === 0 ? "" : 'px') + ';\n' + '}\n\n'; + imageData.images.forEach(function (meta, idx) { + fileContents += '.' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + + ':extend(.' + placeholder + ') {\n' + + ' width: ' + intToPixel(meta.width) + ';\n' + + ' height: ' + intToPixel(meta.height) + ';\n' + + ' background-position: 0 ' + intToPixel(-meta.offsetY) + ';\n' + + '}\n\n'; }); return fileContents; @@ -100,13 +117,21 @@ module.exports = function(grunt) { var fileContents = ''; fileContents += '$' + placeholder + '\n background: url("' + generateBackgroundImagePath() + '") no-repeat\n\n'; - imageData.heights.forEach(function (height, idx) { - fileContents += '$' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + '\n @extend $' + placeholder + '\n background-position: 0 ' + ( height > 0 ? -height + 'px' : 0 ) + '\n\n'; + imageData.images.forEach(function (meta, idx) { + fileContents += '$' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + + '\n @extend $' + placeholder + + '\n width: ' + intToPixel(meta.width) + + '\n height: ' + intToPixel(meta.height) + + '\n background-position: 0 ' + intToPixel(-meta.offsetY) + '\n\n'; }); return fileContents; } + function intToPixel (int) { + return int !== 0 ? int + 'px' : 0; + } + function runSpriteGenerator (images) { // spawn a phantom js process var ps = spawn(binPath, ['--web-security=no', path.resolve(__dirname, '../lib/phantomspriter.js')]); @@ -153,19 +178,19 @@ module.exports = function(grunt) { switch (output){ case "scss": - stylesData = generateSASSFile(incomingData, images, placeHolder, true); + stylesData = generateSASSFile(incomingData.meta, images, placeHolder, true); break; case "sass": - stylesData = generateSASSFile(incomingData, images, placeHolder); + stylesData = generateSASSFile(incomingData.meta, images, placeHolder); break; case "less": - stylesData = generateLESSFile(incomingData, images, placeHolder); + stylesData = generateLESSFile(incomingData.meta, images, placeHolder); break; case "stylus": - stylesData = generateStylusFile(incomingData, images, placeHolder); + stylesData = generateStylusFile(incomingData.meta, images, placeHolder); break; default: - stylesData = generateCSSFile(incomingData, images); + stylesData = generateCSSFile(incomingData.meta, images); break; } From a620ecd75db5a17c32a4209ffbb2acf8afd815e0 Mon Sep 17 00:00:00 2001 From: alpadev Date: Tue, 1 Apr 2014 01:40:52 +0200 Subject: [PATCH 3/6] Version bump @0.3.4 ### 0.3.4 + Added width and height properties to the spriter output [@alpadev] (https://github.com/alpadev) - 85a04f58 Updates the generator functions to adopt the changes introduced to the spriter script. See #52 [@alpadev] - 6416c26d Rewrote most of it.. to accomplish #52 (also the old code been a lil dirty imo :)) [@alpadev] --- README.md | 6 +++++- package.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f178479..0342cb1 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ jpgmin: { } ``` -If you would like to use lossy compression via `jpegoptim`'s `-m` flag, you can +If you would like to use lossy compression via `jpegoptim`'s `-m` flag, you can add a `quality` configuration option: ```javascript @@ -295,6 +295,10 @@ would generate something like this: ## Release History +### 0.3.4 ++ Added width and height properties to the spriter output [@alpadev] (https://github.com/alpadev) + - 85a04f58 Updates the generator functions to adopt the changes introduced to the spriter script. See #52 [@alpadev] + - 6416c26d Rewrote most of it.. to accomplish #52 (also the old code been a lil dirty imo :)) [@alpadev] ### 0.3.3 + Added Stylus ouput option to sprites task [Thx to @alpadev] (https://github.com/alpadev) diff --git a/package.json b/package.json index 6ebbaa0..778ad8f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "grunt-imagine", "description": "Grunt tasks for optimizing, inlining & spriting images", - "version": "0.3.3", + "version": "0.3.4", "homepage": "http://asciidisco.github.com/grunt-imagine/", "author": { "name": "asciidisco", From 899968c62626b0c244e48e66fe525a90eb157959 Mon Sep 17 00:00:00 2001 From: alpadev Date: Thu, 3 Apr 2014 21:43:02 +0200 Subject: [PATCH 4/6] Adds "dimensions" config flag examples (false by default) --- Gruntfile.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 5321fa7..6611902 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -47,13 +47,15 @@ module.exports = function (grunt) { icons36: { src: ['test/out/img/icons36/*.png'], css: 'test/out/css/icons36.css', - map: 'test/out/img/icons36.png' + map: 'test/out/img/icons36.png', + dimensions: true }, icons36_scss: { src: ['test/out/img/icons36/*.png'], css: 'test/out/scss/icons36.scss', map: 'test/out/img/icons36_scss.png', - output: 'scss' + output: 'scss', + dimensions: false }, icons36_sass: { src: ['test/out/img/icons36/*.png'], From 9effbb3b5e3216ccd87d72d0aceeab9b017f9040 Mon Sep 17 00:00:00 2001 From: alpadev Date: Thu, 3 Apr 2014 21:52:02 +0200 Subject: [PATCH 5/6] Updates the output generators accordingly --- tasks/sprites.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tasks/sprites.js b/tasks/sprites.js index 3404b9e..36ec999 100644 --- a/tasks/sprites.js +++ b/tasks/sprites.js @@ -20,7 +20,8 @@ module.exports = function(grunt) { margin = !_.isUndefined(this.data.margin) ? parseInt(this.data.margin, 10) : 0, externalData = '', classPrefix = _.isUndefined(this.data.classPrefix) ? '' : this.data.classPrefix, - output = !_.isUndefined(this.data.output) ? this.data.output.toLowerCase() : "css"; + output = !_.isUndefined(this.data.output) ? this.data.output.toLowerCase() : "css", + addSize = !!this.data.dimensions; // check if the margin setting is a number if (_.isNaN(margin)) { @@ -69,8 +70,8 @@ module.exports = function(grunt) { imageData.images.forEach(function (meta, idx) { fileContents += '.' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + ' {\n' + - ' width: ' + intToPixel(meta.width) + ';\n' + - ' height: ' + intToPixel(meta.height) + ';\n' + + (addSize && ' width: ' + intToPixel(meta.width) + ';\n' || '') + + (addSize && ' height: ' + intToPixel(meta.height) + ';\n' || '') + ' background-position: 0 ' + intToPixel(-meta.offsetY) + ';\n' + '}\n\n'; }); @@ -87,8 +88,8 @@ module.exports = function(grunt) { fileContents += '%' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + (scssSyntax ? ' {' : '') + '\n' + ' @extend ' + '%' + placeholder + colon + - ' width: ' + intToPixel(meta.width) + colon + - ' height: ' + intToPixel(meta.height) + colon + + (addSize && ' width: ' + intToPixel(meta.width) + colon || '') + + (addSize && ' height: ' + intToPixel(meta.height) + colon || '') + ' background-position: 0 ' + intToPixel(-meta.offsetY) + colon + (scssSyntax ? '}' : '') + '\n\n'; }); @@ -104,8 +105,8 @@ module.exports = function(grunt) { imageData.images.forEach(function (meta, idx) { fileContents += '.' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + ':extend(.' + placeholder + ') {\n' + - ' width: ' + intToPixel(meta.width) + ';\n' + - ' height: ' + intToPixel(meta.height) + ';\n' + + (addSize && ' width: ' + intToPixel(meta.width) + ';\n' || '') + + (addSize && ' height: ' + intToPixel(meta.height) + ';\n' || '') + ' background-position: 0 ' + intToPixel(-meta.offsetY) + ';\n' + '}\n\n'; }); @@ -120,8 +121,8 @@ module.exports = function(grunt) { imageData.images.forEach(function (meta, idx) { fileContents += '$' + (classPrefix === '' ? '' : classPrefix + '-') + path.basename(images[idx].file, '.png') + '\n @extend $' + placeholder + - '\n width: ' + intToPixel(meta.width) + - '\n height: ' + intToPixel(meta.height) + + (addSize && '\n width: ' + intToPixel(meta.width) || '') + + (addSize && '\n height: ' + intToPixel(meta.height) || '') + '\n background-position: 0 ' + intToPixel(-meta.offsetY) + '\n\n'; }); From 829044a56a9fcc2b4b5338765f2bb20ce1030ed2 Mon Sep 17 00:00:00 2001 From: alpadev Date: Thu, 3 Apr 2014 22:22:41 +0200 Subject: [PATCH 6/6] Updates the README with details about the setting --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README.md b/README.md index 0342cb1..85b3ef9 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,46 @@ would generate something like this: ``` +##### dimensions + +This will add the CSS "width" and "height" properties to the tasks' output. This setting is **false** by default. + +For example, the following configuration: + +```javascript + sprites: { + icons36: { + src: ['test/out/img/icons36/*.png'], + css: 'test/out/scss/icons36.scss', + map: 'test/out/img/icons36.png', + output: 'scss', + dimensions: true + } + } +``` + +would generate something like this: + +```css +%icons36 { + background: url("../img/icons36.png") no-repeat; + } + +%sprite_01 { + @extend %icons36; + width: 32px; + height: 32px; + background-position: 0 0; +} + +%sprite_02 { + @extend %icons36; + width: 48px; + height: 48px; + background-position: 0 -32px; +} +``` + ## Future (TODO) * Better documentation (Near future!) * JS only PNG optimizing