function cssTemplate(list) { var stylePath = path.relative(opts.cssPath, opts.imgPath); var styles = []; _.forEach(list, function(item) { var classname = item.meta.name; var newClassName = item.meta.baseDir + opts.connector + item.meta.name; var name = duplicateClassname(classnames, classname, newClassName); styles.push({ 'name': name, 'x': item.x, 'y': item.y, 'width': item.width, 'height': item.height }); }); return templater({ sprites: styles, spritesheet: { width: opts.info.width, height: opts.info.height, image: path.join(stylePath, opts.spriteName + opts.connector + opts.baseName + "." + opts.format) }}, { format: 'sprite', formatOpts: { 'cssClass': opts.prefix, 'connector': opts.connector, 'processor': opts.processor } } ); }
function writeCSS(spritesmithResult, callback) { var templaterData = convertSpritesmithResultToSpritesheetTemplatesFormat(spritesmithResult); var code = spritesheetTemplater(templaterData, options.spritesheetTemplatesOptions); writeFileR( options.target.css, code, callback ); }
opts.info.forEach(function(sprites, key) { var width = sprites.width, height = sprites.height; var stylePath, styleName, spritesData = []; _.forEach(sprites.items, function(item) { cssPath = path.join(opts.cssPath); imgPath = path.join(opts.imgPath); stylePath = path.relative(cssPath, imgPath); styleName = item.meta.baseDir; var classname = item.meta.name; var newClassName = item.meta.baseDir + opts.connector + item.meta.name; var name = duplicateClassname(classnames, classname, newClassName); spritesData.push({ 'name': name, 'x': item.x, 'y': item.y, 'width': item.width, 'height': item.height, }); }); if (opts.useImport) { var _cssPath = opts.cssPath; stylePath = path.relative(_cssPath, imgPath); } var template = templater({ sprites: spritesData, spritesheet: { width: width, height: height, image: path.join(stylePath, opts.spriteName + opts.connector + styleName + "." + opts.format) }},{ format: 'sprite', formatOpts: { 'cssClass': opts.prefix, 'connector': opts.connector, 'processor': opts.processor } } ); templates.push({ name: opts.spriteName + opts.connector + styleName, template: template, cssPath: cssPath }); spritesData = []; });
spritesmith.createImages(paths, (err, images) => { if (err) { return done(err); } var result = spritesmith.processImages(images, options.spritesmith); var coordinates_formatted = Object.keys(result.coordinates).map( (key) => ({ name: path.basename( key, path.extname( key ) ), x: result.coordinates[key].x, y: result.coordinates[key].y, width: result.coordinates[key].width, height: result.coordinates[key].height }) ); var css_output = templater({ sprites: coordinates_formatted, spritesheet: { width: result.properties.width, height: result.properties.height, image: path.posix.relative( path.dirname( options.css_dest ), options.image_dest ) } }, options.templater); files[options.css_dest] = { contents: new Buffer(css_output), mode: '0644' }; streamToBuffer(result.image, (err, buffer) => { files[options.image_dest] = { contents: buffer, mode: '0644' }; done(); }); if(options.removeSrc){ Object.keys(result.coordinates).forEach((file) => {delete files[file.slice(4)];}); } });
function (results, callback) { addCoordinates(groupByNormalName, 'normalCoordinates', results[0].coordinates); addCoordinates(groupByRetinaName, 'retinaCoordinates', results[1].coordinates); var normalSprites = getSpritesForSpritesheetTemplates('', 'normalCoordinates'); var retinaSprites = getSpritesForSpritesheetTemplates('retina_', 'retinaCoordinates'); var spritesheetTemplatesData = { sprites: normalSprites, spritesheet: { width: results[0].properties.width, height: results[0].properties.height, image: options.apiOptions.cssImageRef }, retina_sprites: retinaSprites, retina_spritesheet: { width: results[1].properties.width, height: results[1].properties.height, image: options.retina.cssImageRef }, retina_groups: _.values(grouppedSources).map(function (sprite, i) { return { name: sprite.apiName, index: i }; }) }; var apiCode = spritesheetTemplater( spritesheetTemplatesData, options.spritesheetTemplatesOptions ); async.parallel([ writeFileR.bind(null, options.target.css, apiCode), writeFileR.bind(null, options.target.image, results[0].image, 'binary'), writeFileR.bind(null, options.retina.targetImage, results[1].image, 'binary'), ], callback) }
], function handleImages(err, resultArr) { // If an error occurred, emit it if (err) { return cb(err); } // Otherwise, validate our images line up var normalSprites = resultArr[0]; var retinaSprites = resultArr[1]; // If we have retina images, verify the widths line up if (retinaSprites) { // Perform our assertions var errorEncountered = false; normalSprites.forEach(function validateImageSizes(normalSprite, i) { var retinaSprite = retinaSprites[i]; if (retinaSprite.width !== normalSprite.width * 2 || retinaSprite.height !== normalSprite.height * 2) { errorEncountered = true; var err = new Error('Normal sprite has inconsistent size with retina sprite. ' + '"' + images[i].path + '" is ' + normalSprite.width + 'x' + normalSprite.height + ' while ' + '"' + retinaImages[i].path + '" is ' + retinaSprite.width + 'x' + retinaSprite.height + '.'); err.normalSprite = normalSprite; err.retinaSprite = retinaSprite; that.emit('error', err); } }); // If there was an error, then bail out if (errorEncountered) { imgStream.push(null); cssStream.push(null); return cb(); } } // Process our images now var result = spritesmith.processImages(normalSprites, spritesmithParams); var retinaResult; if (retinaSprites) { retinaResult = retinaSpritesmith.processImages(retinaSprites, retinaSpritesmithParams); } // START OF DUPLICATE CODE FROM grunt-spritesmith // Generate a listing of CSS variables var coordinates = result.coordinates; var properties = result.properties; var spritePath = params.imgPath || url.relative(cssName, imgName); var spritesheetData = { width: properties.width, height: properties.height, image: spritePath }; var cssVarMap = params.cssVarMap || function noop() {}; var cleanCoords = []; // Clean up the file name of the file Object.getOwnPropertyNames(coordinates).sort().forEach(function (file) { // Extract out our name var name = getCoordinateName(file); var coords = coordinates[file]; // Specify the image for the sprite coords.name = name; coords.source_image = file; // DEV: `image`, `total_width`, `total_height` are deprecated as they are overwritten in `spritesheet-templates` coords.image = spritePath; coords.total_width = properties.width; coords.total_height = properties.height; // Map the coordinates through cssVarMap coords = cssVarMap(coords) || coords; // Save the cleaned name and coordinates cleanCoords.push(coords); }); // If we have retina sprites var retinaCleanCoords; // eslint-disable-line var retinaGroups; // eslint-disable-line var retinaSpritesheetInfo; // eslint-disable-line if (retinaResult) { // Generate a listing of CSS variables var retinaCoordinates = retinaResult.coordinates; var retinaProperties = retinaResult.properties; var retinaSpritePath = params.retinaImgPath || url.relative(cssName, retinaImgName); retinaSpritesheetInfo = { width: retinaProperties.width, height: retinaProperties.height, image: retinaSpritePath }; // DEV: We reuse cssVarMap retinaCleanCoords = []; // Clean up the file name of the file Object.getOwnPropertyNames(retinaCoordinates).sort().forEach(function prepareRetinaTemplateData(file) { var name = getCoordinateName(file); var coords = retinaCoordinates[file]; coords.name = name; coords.source_image = file; coords.image = retinaSpritePath; coords.total_width = retinaProperties.width; coords.total_height = retinaProperties.height; coords = cssVarMap(coords) || coords; retinaCleanCoords.push(coords); }); // Verify we have no conflicting file names (e.g. `1x/home.png` and `2x/home.png`) // https://github.com/twolfson/gulp.spritesmith/issues/124 var cleanCoordNames = _.pluck(cleanCoords, 'name'); var retinaCleanCoordNames = _.pluck(retinaCleanCoords, 'name'); var intersectingNames = _.intersection(cleanCoordNames, retinaCleanCoordNames); if (intersectingNames.length) { throw new Error('Normal and retina sprites have same names: ' + JSON.stringify(intersectingNames) + '. ' + 'Please rename them to different names (e.g. `-1x`, `-2x`) or use `cssVarMap` to prevent collisions. ' + 'See https://github.com/twolfson/gulp.spritesmith/issues/124 for more info'); } // Generate groups for our coordinates retinaGroups = cleanCoords.map(function getRetinaGroups(normalSprite, i) { // Generate our group // DEV: Name is inherited from `cssVarMap` on normal sprite return { name: normalSprite.name, index: i }; }); } // If we have handlebars helpers, register them var handlebarsHelpers = params.cssHandlebarsHelpers; if (handlebarsHelpers) { Object.keys(handlebarsHelpers).forEach(function registerHelper(helperKey) { templater.registerHandlebarsHelper(helperKey, handlebarsHelpers[helperKey]); }); } // If there is a custom template, use it var cssFormat = 'spritesmith-custom'; var cssTemplate = params.cssTemplate; if (cssTemplate) { if (typeof cssTemplate === 'function') { templater.addTemplate(cssFormat, cssTemplate); } else { templater.addHandlebarsTemplate(cssFormat, fs.readFileSync(cssTemplate, 'utf8')); } // Otherwise, override the cssFormat and fallback to 'json' } else { cssFormat = params.cssFormat; if (!cssFormat) { cssFormat = cssFormats.get(cssName) || 'json'; // If we are dealing with retina items, move to retina flavor (e.g. `scss` -> `scss_retina`) if (retinaGroups) { cssFormat += '_retina'; } } } // Render the variables via `spritesheet-templates` var cssStr = templater({ sprites: cleanCoords, spritesheet: spritesheetData, spritesheet_info: { name: params.cssSpritesheetName }, retina_groups: retinaGroups, retina_sprites: retinaCleanCoords, retina_spritesheet: retinaSpritesheetInfo, retina_spritesheet_info: { name: params.cssRetinaSpritesheetName }, retina_groups_info: { name: params.cssRetinaGroupsName } }, { format: cssFormat, formatOpts: params.cssOpts || {} }); // END OF DUPLICATE CODE FROM grunt-spritesmith // Pipe out images as streams and forward their errors // TODO: Consider making joint stream default // but allow for split stream which has more distinct errors // e.g. spritesmith.split() = {css, img} result.image.on('error', function forwardImgError(err) { that.emit('error', err); }); var imgFile = new Vinyl({ path: imgName, contents: result.image }); that.push(imgFile); imgStream.push(imgFile); if (retinaResult) { var retinaImgFile = new Vinyl({ path: retinaImgName, contents: retinaResult.image }); retinaResult.image.on('error', function forwardImgError(err) { that.emit('error', err); }); that.push(retinaImgFile); imgStream.push(retinaImgFile); } // Close our image stream imgStream.push(null); // Output the CSS var cssFile = new Vinyl({ path: cssName, contents: new Buffer(cssStr) }); that.push(cssFile); cssStream.push(cssFile); cssStream.push(null); cb(); });