2015-09-12 00:59:06 +00:00
import gulp from 'gulp' ;
import imagemin from 'gulp-imagemin' ;
import spritesmith from 'gulp.spritesmith' ;
2015-11-08 01:09:51 +00:00
import clean from 'rimraf' ;
2015-09-12 00:59:06 +00:00
import sizeOf from 'image-size' ;
2015-09-13 01:43:04 +00:00
import mergeStream from 'merge-stream' ;
2015-09-12 16:09:29 +00:00
import { basename } from 'path' ;
2015-09-12 00:59:06 +00:00
import { sync } from 'glob' ;
2015-09-13 01:43:04 +00:00
import { each } from 'lodash' ;
2015-09-12 00:59:06 +00:00
// https://github.com/Ensighten/grunt-spritesmith/issues/67#issuecomment-34786248
const MAX _SPRITESHEET _SIZE = 1024 * 1024 * 3 ;
2016-09-16 15:18:07 +00:00
const DIST _PATH = 'website/assets/sprites/dist/' ;
2015-09-12 00:59:06 +00:00
2016-11-18 18:20:25 +00:00
const IMG _DIST _PATH _NEW _CLIENT = 'website/static/sprites/' ;
const CSS _DIST _PATH _NEW _CLIENT = 'website/client/assets/css/sprites/' ;
2015-09-13 01:43:04 +00:00
gulp . task ( 'sprites:compile' , [ 'sprites:clean' , 'sprites:main' , 'sprites:largeSprites' , 'sprites:checkCompiledDimensions' ] ) ;
2015-09-12 00:59:06 +00:00
2015-09-13 01:43:04 +00:00
gulp . task ( 'sprites:main' , ( ) => {
2016-09-16 15:18:07 +00:00
let mainSrc = sync ( 'website/assets/sprites/spritesmith/**/*.png' ) ;
2015-09-13 02:04:38 +00:00
return createSpritesStream ( 'main' , mainSrc ) ;
2015-09-13 01:43:04 +00:00
} ) ;
2015-09-12 00:59:06 +00:00
2015-09-13 01:43:04 +00:00
gulp . task ( 'sprites:largeSprites' , ( ) => {
2016-09-16 15:18:07 +00:00
let largeSrc = sync ( 'website/assets/sprites/spritesmith_large/**/*.png' ) ;
2015-09-13 02:04:38 +00:00
return createSpritesStream ( 'largeSprites' , largeSrc ) ;
2015-09-13 01:43:04 +00:00
} ) ;
2015-09-12 15:24:06 +00:00
2015-09-12 00:59:06 +00:00
gulp . task ( 'sprites:clean' , ( done ) => {
2016-11-18 18:20:25 +00:00
clean ( ` { ${ DIST _PATH } spritesmith*, ${ IMG _DIST _PATH _NEW _CLIENT } spritesmith*, ${ CSS _DIST _PATH _NEW _CLIENT } spritesmith*} ` , done ) ;
2015-09-12 00:59:06 +00:00
} ) ;
2015-09-13 01:43:04 +00:00
gulp . task ( 'sprites:checkCompiledDimensions' , [ 'sprites:main' , 'sprites:largeSprites' ] , ( ) => {
2015-09-12 00:59:06 +00:00
console . log ( 'Verifiying that images do not exceed max dimensions' ) ;
let numberOfSheetsThatAreTooBig = 0 ;
2015-09-12 15:51:15 +00:00
let distSpritesheets = sync ( ` ${ DIST _PATH } *.png ` ) ;
2015-09-12 00:59:06 +00:00
2015-09-12 01:53:32 +00:00
each ( distSpritesheets , ( img , index ) => {
2015-09-13 02:04:38 +00:00
let spriteSize = calculateImgDimensions ( img ) ;
2015-09-12 00:59:06 +00:00
if ( spriteSize > MAX _SPRITESHEET _SIZE ) {
numberOfSheetsThatAreTooBig ++ ;
2015-09-12 16:09:29 +00:00
let name = basename ( img , '.png' ) ;
2016-02-18 08:52:09 +00:00
console . error ( ` WARNING: ${ name } might be too big - ${ spriteSize } > ${ MAX _SPRITESHEET _SIZE } ` ) ;
2015-09-12 00:59:06 +00:00
}
} ) ;
if ( numberOfSheetsThatAreTooBig > 0 ) {
2016-02-18 08:52:09 +00:00
console . error ( ` ${ numberOfSheetsThatAreTooBig } sheets might too big for mobile Safari to be able to handle them, but there is a margin of error in these calculations so it is probably okay. Mention this to an admin so they can test a staging site on mobile Safari after your PR is merged. ` ) ; // https://github.com/HabitRPG/habitrpg/pull/6683#issuecomment-185462180
2015-09-12 13:27:05 +00:00
} else {
console . log ( 'All images are within the correct dimensions' ) ;
2015-09-12 00:59:06 +00:00
}
} ) ;
2016-09-18 19:51:20 +00:00
function createSpritesStream ( name , src ) {
2015-09-13 02:04:38 +00:00
let spritesheetSliceIndicies = calculateSpritesheetsSrcIndicies ( src ) ;
2015-09-13 01:43:04 +00:00
let stream = mergeStream ( ) ;
2015-09-12 16:09:29 +00:00
each ( spritesheetSliceIndicies , ( start , index ) => {
let slicedSrc = src . slice ( start , spritesheetSliceIndicies [ index + 1 ] ) ;
2015-09-13 01:43:04 +00:00
let spriteData = gulp . src ( slicedSrc )
. pipe ( spritesmith ( {
imgName : ` spritesmith- ${ name } - ${ index } .png ` ,
cssName : ` spritesmith- ${ name } - ${ index } .css ` ,
algorithm : 'binary-tree' ,
padding : 1 ,
2016-09-16 15:18:07 +00:00
cssTemplate : 'website/assets/sprites/css/css.template.handlebars' ,
2016-11-18 18:20:25 +00:00
cssVarMap : cssVarMap ,
2015-09-13 01:43:04 +00:00
} ) ) ;
let imgStream = spriteData . img
. pipe ( imagemin ( ) )
2016-11-18 18:20:25 +00:00
. pipe ( gulp . dest ( IMG _DIST _PATH _NEW _CLIENT ) )
2015-09-13 01:43:04 +00:00
. pipe ( gulp . dest ( DIST _PATH ) ) ;
let cssStream = spriteData . css
2016-11-18 18:20:25 +00:00
. pipe ( gulp . dest ( CSS _DIST _PATH _NEW _CLIENT ) )
2015-09-13 01:43:04 +00:00
. pipe ( gulp . dest ( DIST _PATH ) ) ;
stream . add ( imgStream ) ;
stream . add ( cssStream ) ;
2015-09-12 16:09:29 +00:00
} ) ;
2015-09-13 01:43:04 +00:00
return stream ;
2015-09-12 16:09:29 +00:00
}
2016-09-18 19:51:20 +00:00
function calculateSpritesheetsSrcIndicies ( src ) {
2015-09-12 00:59:06 +00:00
let totalPixels = 0 ;
2015-09-12 13:27:05 +00:00
let slices = [ 0 ] ;
2015-09-12 00:59:06 +00:00
2015-09-12 15:24:06 +00:00
each ( src , ( img , index ) => {
2015-09-13 02:04:38 +00:00
let imageSize = calculateImgDimensions ( img , true ) ;
2015-09-12 13:27:05 +00:00
totalPixels += imageSize ;
2015-09-12 00:59:06 +00:00
2015-09-12 13:27:05 +00:00
if ( totalPixels > MAX _SPRITESHEET _SIZE ) {
slices . push ( index - 1 ) ;
totalPixels = imageSize ;
}
} ) ;
2015-09-12 00:59:06 +00:00
2015-09-12 13:27:05 +00:00
return slices ;
2015-09-12 00:59:06 +00:00
}
2016-09-18 19:51:20 +00:00
function calculateImgDimensions ( img , addPadding ) {
2015-09-12 00:59:06 +00:00
let dims = sizeOf ( img ) ;
2015-09-13 02:04:38 +00:00
let requiresSpecialTreatment = checkForSpecialTreatment ( img ) ;
2015-09-12 13:27:05 +00:00
if ( requiresSpecialTreatment ) {
let newWidth = dims . width < 90 ? 90 : dims . width ;
let newHeight = dims . height < 90 ? 90 : dims . height ;
dims = {
width : newWidth ,
2016-09-18 19:51:20 +00:00
height : newHeight ,
2015-09-12 13:27:05 +00:00
} ;
}
let padding = 0 ;
if ( addPadding ) {
padding = ( dims . width * 8 ) + ( dims . height * 8 ) ;
}
2016-09-18 19:51:20 +00:00
if ( ! dims . width || ! dims . height ) console . error ( 'MISSING DIMENSIONS:' , dims ) ;
2015-09-12 00:59:06 +00:00
2015-09-12 13:27:05 +00:00
let totalPixelSize = ( dims . width * dims . height ) + padding ;
2015-09-12 00:59:06 +00:00
return totalPixelSize ;
}
2016-09-18 19:51:20 +00:00
function checkForSpecialTreatment ( name ) {
2016-05-10 21:07:46 +00:00
let regex = /^hair|skin|beard|mustach|shirt|flower|^headAccessory_special_\w+Ears|^eyewear_special_\w+TopFrame/ ;
2015-09-12 13:27:05 +00:00
return name . match ( regex ) || name === 'head_0' ;
}
2016-09-18 19:51:20 +00:00
function cssVarMap ( sprite ) {
2015-09-12 00:59:06 +00:00
// For hair, skins, beards, etc. we want to output a '.customize-options.WHATEVER' class, which works as a
// 60x60 image pointing at the proper part of the 90x90 sprite.
// We set up the custom info here, and the template makes use of it.
2015-09-13 02:04:38 +00:00
let requiresSpecialTreatment = checkForSpecialTreatment ( sprite . name ) ;
2015-09-12 13:27:05 +00:00
if ( requiresSpecialTreatment ) {
2015-09-12 00:59:06 +00:00
sprite . custom = {
px : {
offset _x : ` - ${ sprite . x + 25 } px ` ,
offset _y : ` - ${ sprite . y + 15 } px ` ,
width : '60px' ,
2016-09-18 19:51:20 +00:00
height : '60px' ,
} ,
} ;
2015-09-12 00:59:06 +00:00
}
if ( ~ sprite . name . indexOf ( 'shirt' ) )
sprite . custom . px . offset _y = ` - ${ sprite . y + 30 } px ` ; // even more for shirts
2016-11-17 16:22:48 +00:00
if ( ~ sprite . name . indexOf ( 'hair_base' ) ) {
let styleArray = sprite . name . split ( '_' ) . slice ( 2 , 3 ) ;
if ( Number ( styleArray [ 0 ] ) > 14 )
sprite . custom . px . offset _y = ` - ${ sprite . y } px ` ; // don't crop updos
}
2015-09-12 00:59:06 +00:00
}