Skip to content

Commit

Permalink
enabled - single and multiple modes
Browse files Browse the repository at this point in the history
  • Loading branch information
AtuyL committed Oct 21, 2013
1 parent 5c7e2dd commit 80a2bc9
Show file tree
Hide file tree
Showing 57 changed files with 198 additions and 120 deletions.
25 changes: 19 additions & 6 deletions Gruntfile.coffee
Expand Up @@ -6,18 +6,31 @@ module.exports = (grunt)->
@loadTasks 'tasks'
stylsprite = require('./')
stylspriteOptions =
prefix:'$'
rootPath:'test/src'
pixelRatio:2
debug:true

@initConfig
clean:[
'test/src/img/$*.png'
'test/dest/img/$*.png'
]
clean:['test/dest/**/*']
stylsprite:
options: stylspriteOptions
test:'test/src/img/**'
allinone:files:['test/src/img/allinone.png':'test/src/img/**/*']
nodest:'test/src/img/**/*'
srcdest:files:['test/src/img/srcdest.png':'test/src/img/*']
multisrc:
options:test:true
files:['test/src/img/multisrc.png':['test/src/img/icons','test/src/img/subdir/icons/*']]
hasdestexpand:files:[
expand: true
cwd: 'test/src/img'
src: ['*']
dest: 'test/src/img'
]
nodestexpand:files:[
expand: true
cwd: 'test/src/img'
src: ['*']
]
copy:
test: files: [
expand: true
Expand Down
131 changes: 57 additions & 74 deletions index.coffee
Expand Up @@ -2,105 +2,88 @@ os = require 'os'
fs = require 'fs'
path = require 'path'
stylus = require 'stylus'
crypto = require 'crypto'
imagesize = require('imagesize').Parser
sumpath = require './lib/sumpath'

plugin = (cssPath,options)->
# console.log options
options ?= {}
plugin = (cssPath,options={})->
TMPDIR = do os.tmpdir

hash = (value)->
md5sum = crypto.createHash 'md5'
md5sum.update value,'utf8'
md5sum.digest('hex')

rootPath = options.rootPath or ''
pixelRatio = options.pixelRatio or 1

getImagePath = (params)->
parseUrl = (params)->
if params.args
urlArgs = params.args.nodes[0]
if urlArgs.nodes.length
urlChain = []
for value in urlArgs.nodes
urlChain.push value.string
return urlChain.join ''
url = (value.string for value in urlArgs.nodes).join ''
else
return urlArgs.nodes[0]
url = urlArgs.nodes[0]
else
return params.val
url = params.val

convertToLocalPath = (url)->
parsePath = (url)->
if /^\//i.test url
path.resolve path.join rootPath,url
path.join path.relative(cssPath,rootPath),url
else if not /^https?:\/\//i.test url
path.resolve cssPath,url
url
else
throw new Error 'sorry. unsupport yet.. : ' + url

stylsprite = (params)->
imagePath = getImagePath params # hoge/$fuga/foo.png
localPath = convertToLocalPath imagePath # /User/Piyo/Project/hoge/$fuga/foo.png

extName = path.extname localPath # .png
dirName = path.dirname localPath # /User/Piyo/Project/hoge/$fuga

jsonPath = path.join os.tmpdir(),sumpath.json(path.resolve dirName)

backgroundImage = null
backgroundPosition = null
backgroundSize = null
backgroundRepeat = null
width = null
height = null
if fs.existsSync jsonPath

jsonStr = fs.readFileSync jsonPath
json = JSON.parse jsonStr.toString()
stylsprite = (url,pixelRatio)->
jsonFile = hash(do process.cwd) + '.json'
jsonPath = path.join TMPDIR,jsonFile
jsonData = if fs.existsSync jsonPath then JSON.parse fs.readFileSync jsonPath else null

url = "#{path.dirname path.dirname imagePath}/#{json.name}-#{json.shortsum}.png"
url = parseUrl url
imagePath = parsePath url
pixelRatio = parseFloat(pixelRatio?.val or options.pixelRatio) or 1

targetPath = path.join cssPath,imagePath

spriteWidth = json.width
spriteHeight = json.height
nodesIndex = this.closestBlock.index + 1
backgroundRepeat = new stylus.nodes.Property ['background-repeat'],"no-repeat"

spriteTokenName = path.basename localPath,extName # foo
for token in json.images when token.name is spriteTokenName
x = token.x
y = token.y
width = token.width
height = token.height
if pixelRatio isnt 1
x /= pixelRatio
y /= pixelRatio
width /= pixelRatio
height /= pixelRatio
spriteWidth /= pixelRatio
spriteHeight /= pixelRatio
backgroundSize = new stylus.nodes.Property ['background-size'],"#{spriteWidth}px #{spriteHeight}px"
backgroundPosition = new stylus.nodes.Property ['background-position'],"#{-x}px #{-y}px"
for spriteId,spriteData of jsonData when targetPath.indexOf(spriteId) is 0
itemId = targetPath.replace(spriteId + '/','')
itemData = spriteData.items[itemId]
spriteWidth = spriteData.width / pixelRatio
spriteHeight = spriteData.height / pixelRatio
if itemData
x = itemData.x / pixelRatio
y = itemData.y / pixelRatio
width = itemData.width / pixelRatio
height = itemData.height / pixelRatio
url = imagePath.replace '/' + itemData.id,'.png'
width = new stylus.nodes.Property ["width"],"#{width}px"
height = new stylus.nodes.Property ["height"],"#{height}px"
backgroundImage = new stylus.nodes.Property ['background-image'],"url(#{url})"
else if fs.existsSync localPath
imageData = fs.readFileSync localPath
backgroundPosition = new stylus.nodes.Property ['background-position'],"#{-x}px #{-y}px"
backgroundSize = new stylus.nodes.Property ['background-size'],"#{spriteWidth}px #{spriteHeight}px"
this.closestBlock.nodes.splice nodesIndex,0,width,height,backgroundImage,backgroundPosition,backgroundSize
return null

if fs.existsSync targetPath
imageData = fs.readFileSync targetPath
parser = do imagesize
switch parser.parse imageData
when imagesize.EOF or imagesize.INVALID
console.log 'invalid:',localPath
return null
when imagesize.DONE then {width:width,height:height} = do parser.getResult
if pixelRatio isnt 1
width /= pixelRatio
height /= pixelRatio
backgroundSize = new stylus.nodes.Property ['background-size'],"#{width}px #{height}px"
backgroundImage = new stylus.nodes.Property ['background-image'],"url(#{imagePath})"
else
return new stylus.nodes.Property ['background-image'],"url(#{imagePath})"

backgroundRepeat = new stylus.nodes.Property ['background-repeat'],"no-repeat"
width = new stylus.nodes.Property ["width"],"#{width}px"
height = new stylus.nodes.Property ["height"],"#{height}px"
if backgroundPosition and backgroundSize
this.closestBlock.nodes.splice this.closestBlock.index + 1,0,backgroundPosition,backgroundSize,backgroundRepeat,width,height
else if backgroundPosition
this.closestBlock.nodes.splice this.closestBlock.index + 1,0,backgroundPosition,backgroundRepeat,width,height
else if backgroundSize
this.closestBlock.nodes.splice this.closestBlock.index + 1,0,backgroundSize,width,height
return backgroundImage
return -> (context)->
context.define 'stylsprite',stylsprite
spriteWidth = width / pixelRatio
spriteHeight = height / pixelRatio
width = new stylus.nodes.Property ["width"],"#{spriteWidth}px"
height = new stylus.nodes.Property ["height"],"#{spriteHeight}px"
backgroundImage = new stylus.nodes.Property ['background-image'],"url(#{url})"
backgroundSize = new stylus.nodes.Property ['background-size'],"#{spriteWidth}px #{spriteHeight}px"
this.closestBlock.nodes.splice nodesIndex,0,width,height,backgroundImage,backgroundSize
return null
return null
-> (context)-> context.define 'stylsprite',stylsprite

exports = module.exports = plugin
exports.path = __dirname
6 changes: 0 additions & 6 deletions lib/sumpath.coffee

This file was deleted.

102 changes: 73 additions & 29 deletions tasks/stylsprite.coffee
Expand Up @@ -5,38 +5,49 @@ async = require 'async'
boxpack = require 'boxpack'
crypto = require 'crypto'
imagemagick = require "imagemagick"
sumpath = require '../lib/sumpath'

module.exports = (grunt)->
generate = (src,options,callback)->
src = path.resolve src
TMPDIR = do os.tmpdir

TYPE =
ALL_IN_ONE:'ALL_IN_ONE'
DIRECTORY:'DIRECTORY'
GENERATE:'GENERATE'

REG =
image:/\.(png|gif|jpe?g)$/i

hash = (value)->
md5sum = crypto.createHash 'md5'
md5sum.update src,'utf8'
checksum = md5sum.digest('hex')
shortsum = checksum[0...5]
md5sum.update value,'utf8'
md5sum.digest('hex')

jsondata =
name:path.basename src
checksum:checksum
shortsum:shortsum
width:0
height:0
images:null
$generate = (type,dest,images,options,callback)->
id = dest.replace REG.image,''
items = {}

destpath = src.replace /\/?$/,"-#{shortsum}.png"
images = fs.readdirSync src
images = images.filter (value,index,array)-> /\.(png|gif|jpe?g)$/i.test value
images = images.map (value,index,array)-> path.join src,value
if REG.image.test dest
checksum = hash dest.replace REG.image,''
shortsum = checksum[0...5]
destdir = path.dirname dest
destfile = dest
else
checksum = hash dest
shortsum = checksum[0...5]
destdir = dest
destfile = "#{dest}-#{shortsum}.png"

tasks = for filepath,index in images then do (filepath,index)->
(next)->
imagemagick.identify filepath,(error,image)->
unless error
images[index] =
name:path.basename filepath.replace /\.[^\.]+$/,''
id:path.relative destdir,filepath
filepath:filepath
width:image.width + options.padding
height:image.height + options.padding
next error

async.parallel tasks,->
width = 0
height = 0
Expand All @@ -47,29 +58,62 @@ module.exports = (grunt)->
image.y = rect.y
image.width = rect.width - options.padding
image.height = rect.height - options.padding
items[image.id] = image
width = Math.max width,rect.x + rect.width
height = Math.max height,rect.y + rect.height
stack.push image.filepath,"-geometry","+#{rect.x}+#{rect.y}","-composite"
width -= options.padding
height -= options.padding
stack.unshift "-size","#{width}x#{height}","xc:none"
stack.push destpath
stack.push destfile

imagemagick.convert stack,options.timeout,(error)->
jsondata.width = width
jsondata.height = height
jsondata.images = images
jsonpath = path.join os.tmpdir(),sumpath.json(src)
fs.writeFileSync jsonpath,JSON.stringify(jsondata)
unless error
jsonFile = hash(do process.cwd) + '.json'
jsonPath = path.join TMPDIR,jsonFile
jsonData = if fs.existsSync jsonPath then JSON.parse fs.readFileSync jsonPath else {}
jsonData[id] =
id:id
filepath:destfile
checksum:checksum
shortsum:shortsum
width:width
height:height
items:items
fs.writeFileSync jsonPath,JSON.stringify(jsonData)
callback error

grunt.registerMultiTask 'stylsprite',"wait a minute.",->
done = do @async
options = @options
padding:2
timeout:10000
tasks = for src in @filesSrc then do (src)->
(next)->
if not fs.existsSync src then return next false
else if not fs.statSync(src).isDirectory() then return next false
return generate src,options,next
hasDestDir = @data.files and @data.files[0].dest
tasks = []
for task in @files then do (task)->
dest = null
if not hasDestDir and REG.image.test task.dest
dest = task.dest
images = []
for src in task.src
if do fs.statSync(src).isDirectory
for file in fs.readdirSync src when REG.image.test file
images.push path.join src,file
else if REG.image.test src and not ~images.indexOf src
images.push src
if images.length
tasks.push do (dest,images)-> (next)-> $generate TYPE.ALL_IN_ONE,dest,images,options,next
else if hasDestDir
dest = task.dest
images = []
for src in task.src when do fs.statSync(src).isDirectory
images.push path.join src,file for file in fs.readdirSync src when REG.image.test file
if images.length
tasks.push do (dest,images)-> (next)-> $generate TYPE.DIRECTORY,dest,images,options,next
else
for src in task.src when do fs.statSync(src).isDirectory
dest = src
images = (path.join src,file for file in fs.readdirSync src when REG.image.test file)
if images.length
tasks.push do (dest,images)-> (next)-> $generate TYPE.GENERATE,dest,images,options,next
async.parallel tasks,done

0 comments on commit 80a2bc9

Please sign in to comment.