Skip to content

Commit 8391a08

Browse files
committed
adds base64 support
1 parent 13b03e2 commit 8391a08

File tree

7 files changed

+111
-63
lines changed

7 files changed

+111
-63
lines changed

bin/cli.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ var opts = require('nomnom')
2020
metavar: 'GLOB',
2121
help: 'glob strings to find source images to put into the sprite'
2222
})
23+
.option('base64', {
24+
abbr: 'b',
25+
flag: true,
26+
help: 'instead of creating a sprite, write base64 encoded images to css (css file will be written to <out>)'
27+
})
2328
.option('cssPath', {
2429
abbr: 'c',
2530
full: 'css-image-path',

lib/css-sprite.js

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ var lodash = require('lodash');
66
var path = require('path');
77
var json2css = require('json2css');
88
var File = require('vinyl');
9+
var imageinfo = require('imageinfo');
910
var replaceExtension = require('./replace-extension');
1011
var Image = Canvas.Image;
1112

@@ -26,25 +27,29 @@ module.exports = function (opt) {
2627

2728
var queue = function (img) {
2829
sprites.push({
29-
'img': img,
30+
'img': (!opt.base64) ? img : null,
3031
'name': replaceExtension(file.relative, ''),
31-
'x': opt.orientation === 'vertical' ? opt.margin : ctxWidth + opt.margin,
32-
'y': opt.orientation === 'vertical' ? ctxHeight + opt.margin: opt.margin,
32+
'x': (!opt.base64) ? (opt.orientation === 'vertical' ? opt.margin : ctxWidth + opt.margin) : 0,
33+
'y': (!opt.base64) ? (opt.orientation === 'vertical' ? ctxHeight + opt.margin: opt.margin) : 0,
3334
'width': img.width,
3435
'height': img.height,
35-
'image': path.join(opt.cssPath, opt.name)
36+
'total_width': img.width,
37+
'total_height': img.height,
38+
'image': (!opt.base64) ? path.join(opt.cssPath, opt.name) : 'data:' + imageinfo(file.contents).mimeType + ';base64,' + file.contents.toString('base64')
3639
});
3740

38-
if (opt.orientation === 'vertical') {
39-
ctxHeight = ctxHeight + img.height + 2 * opt.margin;
40-
if (img.width + 2 * opt.margin > ctxWidth) {
41-
ctxWidth = img.width + 2 * opt.margin;
41+
if (!opt.base64) {
42+
if (opt.orientation === 'vertical') {
43+
ctxHeight = ctxHeight + img.height + 2 * opt.margin;
44+
if (img.width + 2 * opt.margin > ctxWidth) {
45+
ctxWidth = img.width + 2 * opt.margin;
46+
}
4247
}
43-
}
44-
else {
45-
ctxWidth = ctxWidth + img.width + 2 * opt.margin;
46-
if (img.height + 2 * opt.margin > ctxHeight) {
47-
ctxHeight = img.height + 2 * opt.margin;
48+
else {
49+
ctxWidth = ctxWidth + img.width + 2 * opt.margin;
50+
if (img.height + 2 * opt.margin > ctxHeight) {
51+
ctxHeight = img.height + 2 * opt.margin;
52+
}
4853
}
4954
}
5055
}
@@ -66,26 +71,30 @@ module.exports = function (opt) {
6671
if (sprites.length === 0) {
6772
return this.emit('end');
6873
}
69-
var canvas = new Canvas(ctxWidth, ctxHeight);
70-
var ctx = canvas.getContext('2d');
71-
lodash.each(sprites, function (sprite) {
72-
sprite.total_width = ctxWidth;
73-
sprite.total_height = ctxHeight;
74-
ctx.drawImage(sprite.img, sprite.x, sprite.y, sprite.width, sprite.height);
75-
});
76-
if (opt.style) {
74+
if (!opt.base64) {
75+
var canvas = new Canvas(ctxWidth, ctxHeight);
76+
var ctx = canvas.getContext('2d');
77+
lodash.each(sprites, function (sprite) {
78+
sprite.total_width = ctxWidth;
79+
sprite.total_height = ctxHeight;
80+
ctx.drawImage(sprite.img, sprite.x, sprite.y, sprite.width, sprite.height);
81+
});
82+
}
83+
if (opt.style || opt.base64) {
7784
var css = json2css(sprites, {'format': opt.processor});
7885
this.emit('data', new File({
79-
base: path.dirname(opt.style),
80-
path: opt.style,
86+
base: (!opt.base64) ? path.dirname(opt.style) : opt.out,
87+
path: (!opt.base64 || (opt.base64 && opt.style)) ? opt.style : path.join(opt.out, replaceExtension(opt.name, '.' + opt.processor)),
8188
contents: new Buffer(css)
8289
}));
8390
}
84-
this.emit('data', new File({
85-
base: opt.out,
86-
path: path.join(opt.out, opt.name),
87-
contents: new Buffer(canvas.toBuffer())
88-
}));
91+
if (!opt.base64) {
92+
this.emit('data', new File({
93+
base: opt.out,
94+
path: path.join(opt.out, opt.name),
95+
contents: new Buffer(canvas.toBuffer())
96+
}));
97+
}
8998
this.emit('end');
9099
}
91100

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "css-sprite",
3-
"version": "0.5.0",
3+
"version": "0.6.0",
44
"description": "css sprite generator",
55
"license": "MIT",
66
"repository": {
@@ -57,7 +57,8 @@
5757
"event-stream": "~3.1.0",
5858
"graceful-fs": "~2.0.1",
5959
"mkdirp": "~0.3.5",
60-
"gaze": "~0.5.0"
60+
"gaze": "~0.5.0",
61+
"imageinfo": "~1.0.4"
6162
},
6263
"devDependencies": {
6364
"mocha": "~1.17.0",

readme.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
> A css sprite generator.
66
7-
> Generates a sprite file and the propper css file out of a directory with images
7+
> Generates a sprite file and the propper css file out of a directory with images. It can also generate style files with base64 encoded images.
88
99
## Requirements
1010

@@ -20,7 +20,7 @@ Install with [npm](https://npmjs.org/package/css-sprite)
2020
npm install css-sprite --save
2121
```
2222

23-
If you want to use `css-sprite` on your cli use:
23+
If you want to use `css-sprite` on your cli install with:
2424

2525
```
2626
npm install css-sprite -g
@@ -35,6 +35,7 @@ out path of directory to write sprite file to
3535
src glob strings to find source images to put into the sprite
3636
3737
Options:
38+
-b, --base64 instead of creating a sprite, write base64 encoded images to css (css file will be written to <out>)
3839
-c, --css-image-path http path to images on the web server (relative to css path or absolute path) [../images]
3940
-n, --name name of the sprite file [sprite.png]
4041
-p, --processor output format of the css. one of css, less, sass, scss or stylus [css]
@@ -59,6 +60,7 @@ sprite.create(options, cb);
5960
* **processor:** output format of the css. one of css, less, sass, scss or stylus [css]
6061
* **orientation:** orientation of the sprite image [vertical]
6162
* **margin:** margin in px between tiles [5]
63+
* **base64:** when true instead of creating a sprite writes base64 encoded images to css (css file will be written to ```<out>```)
6264

6365
### Example
6466
```
@@ -81,17 +83,28 @@ var gulp = require('gulp');
8183
var gulpif = require('gulp-if');
8284
var sprite = require('css-sprite').stream;
8385
86+
// generate sprite.png and _sprite.scss
8487
gulp.task('sprites', function () {
8588
return gulp.src('./src/img/*.png')
8689
.pipe(sprite({
87-
name: 'sprites.png',
88-
style: '_sprites.scss',
90+
name: 'sprite.png',
91+
style: '_sprite.scss',
8992
cssPath: './img',
9093
processor: 'scss'
9194
}))
9295
.pipe(gulpif('*.png', gulp.dest('./dist/img/')))
9396
.pipe(gulpif('*.scss', gulp.dest('./dist/scss/')));
9497
});
98+
// generate scss with base64 encoded images
99+
gulp.task('base64', function () {
100+
return gulp.src('./src/img/*.png')
101+
.pipe(sprite({
102+
base64: true,
103+
style: '_base64.scss',
104+
processor: 'scss'
105+
}))
106+
.pipe(gulp.dest('./dist/scss/'));
107+
});
95108
```
96109

97110
Options to use `css-sprite` with [Gulp](http://gulpjs.com) are the same as for the `sprite.create` function with the exception of `src` and `out`.
@@ -112,12 +125,19 @@ module.exports = function(grunt) {
112125
'orientation': 'vertical',
113126
'margin': 5
114127
},
115-
build: {
128+
sprite: {
116129
options: {
117130
'style': 'dest/css/sprite.css'
118131
},
119132
src: ['src/images/*', 'src/images2/*'],
120133
dest: 'dest/images/sprite.png',
134+
},
135+
base64: {
136+
options: {
137+
'base64': true
138+
},
139+
src: ['src/images/*'],
140+
dest: 'dest/scss/base64.css',
121141
}
122142
}
123143
});
@@ -132,4 +152,5 @@ module.exports = function(grunt) {
132152

133153
Options to use `css-sprite` with [Grunt](http://gruntjs.com) are the same as for the `sprite.create` function with the exception of `src` and `out`.
134154

155+
135156
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/aslansky/css-sprite/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

test/commandline.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,20 @@ describe('css-sprite cli (bin/cli.js)', function () {
1414
function (error, stdout, stderr) {
1515
stderr.should.be.empty;
1616
stdout.should.containEql('Usage:');
17-
stdout.should.containEql('css-sprite <src>');
18-
stdout.should.containEql('--out DIR');
17+
stdout.should.containEql('css-sprite <out> <src>');
1918
done();
2019
});
2120
});
2221
it('should generate sprite', function (done) {
23-
exec('./bin/cli.js -o ./test/dist/ ./test/fixtures/*.png',
22+
exec('./bin/cli.js ./test/dist/ ./test/fixtures/*.png',
2423
function (error, stdout, stderr) {
2524
stderr.should.be.empty;
2625
fs.existsSync('./test/dist/sprite.png').should.be.true;
2726
fs.readFile('./test/dist/sprite.png', function (err, png) {
2827
var img = new Image();
2928
img.src = png;
30-
img.width.should.be.equal(56);
31-
img.height.should.be.equal(125);
29+
img.width.should.equal(56);
30+
img.height.should.equal(125);
3231
fs.unlinkSync('./test/dist/sprite.png');
3332
fs.rmdirSync('./test/dist');
3433
done();

test/css-sprite.js

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ describe('css-sprite (lib/css-sprite.js)', function () {
2020
.pipe(es.map(function (file, cb) {
2121
var img = new Image();
2222
img.src = file.contents;
23-
file.path.should.be.equal('dist/img/sprites.png');
24-
file.relative.should.be.equal('sprites.png');
25-
img.width.should.be.equal(56);
26-
img.height.should.be.equal(125);
23+
file.path.should.equal('dist/img/sprites.png');
24+
file.relative.should.equal('sprites.png');
25+
img.width.should.equal(56);
26+
img.height.should.equal(125);
2727
cb();
2828
}))
2929
.on('end', done);
@@ -38,8 +38,8 @@ describe('css-sprite (lib/css-sprite.js)', function () {
3838
.pipe(es.map(function (file, cb) {
3939
var img = new Image();
4040
img.src = file.contents;
41-
img.width.should.be.equal(86);
42-
img.height.should.be.equal(185);
41+
img.width.should.equal(86);
42+
img.height.should.equal(185);
4343
cb();
4444
}))
4545
.on('end', done);
@@ -54,10 +54,10 @@ describe('css-sprite (lib/css-sprite.js)', function () {
5454
.pipe(es.map(function (file, cb) {
5555
var img = new Image();
5656
img.src = file.contents;
57-
file.path.should.be.equal('dist/img/sprites.png');
58-
file.relative.should.be.equal('sprites.png');
59-
img.width.should.be.equal(110);
60-
img.height.should.be.equal(69);
57+
file.path.should.equal('dist/img/sprites.png');
58+
file.relative.should.equal('sprites.png');
59+
img.width.should.equal(110);
60+
img.height.should.equal(69);
6161
cb();
6262
}))
6363
.on('end', done);
@@ -81,11 +81,11 @@ describe('css-sprite (lib/css-sprite.js)', function () {
8181
}))
8282
.on('end', function () {
8383
png.should.be.ok;
84-
png.path.should.be.equal('dist/img/sprites.png');
85-
png.relative.should.be.equal('sprites.png');
84+
png.path.should.equal('dist/img/sprites.png');
85+
png.relative.should.equal('sprites.png');
8686
css.should.be.ok;
87-
css.path.should.be.equal('./dist/css/sprites.css');
88-
css.relative.should.be.equal('sprites.css');
87+
css.path.should.equal('./dist/css/sprites.css');
88+
css.relative.should.equal('sprites.css');
8989
css.contents.toString('utf-8').should.containEql('.icon-floppy-disk');
9090
done();
9191
});
@@ -110,15 +110,28 @@ describe('css-sprite (lib/css-sprite.js)', function () {
110110
}))
111111
.on('end', function () {
112112
png.should.be.ok;
113-
png.path.should.be.equal('dist/img/sprites.png');
114-
png.relative.should.be.equal('sprites.png');
113+
png.path.should.equal('dist/img/sprites.png');
114+
png.relative.should.equal('sprites.png');
115115
css.should.be.ok;
116-
css.path.should.be.equal('./dist/css/sprites.scss');
117-
css.relative.should.be.equal('sprites.scss');
116+
css.path.should.equal('./dist/css/sprites.scss');
117+
css.relative.should.equal('sprites.scss');
118118
css.contents.toString('utf-8').should.containEql('$floppy-disk');
119119
done();
120120
});
121121
});
122+
it('should return a object stream with a css file with base64 encode images in it', function (done) {
123+
vfs.src('./test/fixtures/**')
124+
.pipe(sprite({
125+
base64: true,
126+
out: './dist/css'
127+
}))
128+
.pipe(es.map(function (file, cb) {
129+
file.relative.should.equal('sprite.css');
130+
file.contents.toString('utf-8').should.containEql('data:image/png;base64');
131+
cb();
132+
}))
133+
.on('end', done);
134+
});
122135
it('should do nothing when no files match', function (done) {
123136
var file = false;
124137
vfs.src('./test/fixtures/empty/**')

test/wrapper.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ describe('css-sprite wrapper (index.js)', function () {
2121
fs.readFile('./test/dist/sprite.png', function (err, png) {
2222
var img = new Image();
2323
img.src = png;
24-
img.width.should.be.equal(56);
25-
img.height.should.be.equal(125);
24+
img.width.should.equal(56);
25+
img.height.should.equal(125);
2626
fs.unlinkSync('./test/dist/sprite.png');
2727
fs.rmdirSync('./test/dist');
2828
done();
@@ -73,9 +73,9 @@ describe('css-sprite wrapper (index.js)', function () {
7373
.pipe(es.map(function (file, cb) {
7474
var img = new Image();
7575
img.src = file.contents;
76-
file.relative.should.be.equal('sprite.png');
77-
img.width.should.be.equal(56);
78-
img.height.should.be.equal(125);
76+
file.relative.should.equal('sprite.png');
77+
img.width.should.equal(56);
78+
img.height.should.equal(125);
7979
cb();
8080
}))
8181
.on('end', done);

0 commit comments

Comments
 (0)