diff --git a/.travis.yml b/.travis.yml index 11e2457..9aeb69f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,18 @@ language: node_js node_js: - - '0.10' -script: 'npm test' +- '0.10' +script: +- npm test after_success: - - 'npm run coverage && npm run coveralls' +- npm run publish env: global: - secure: Ntsmce9vaWJWoAD6aFE9PbufcENR+bM49LvLjjSM+kZ8f92DVngBEwKA9tPh37KNCr935h4MxSJqe+OHQ50ObuJ5wiMJRsXc+4lvC4MLOo2ntIZd2qdol2SR+89LTT9YAiCX3JGnc/Us1KaUBh/hJ9A/OyxUF8rJLy6dDGldnW4= + - secure: Ntsmce9vaWJWoAD6aFE9PbufcENR+bM49LvLjjSM+kZ8f92DVngBEwKA9tPh37KNCr935h4MxSJqe+OHQ50ObuJ5wiMJRsXc+4lvC4MLOo2ntIZd2qdol2SR+89LTT9YAiCX3JGnc/Us1KaUBh/hJ9A/OyxUF8rJLy6dDGldnW4= + - secure: TsnPeT+sp3VGyHnnEJtsgjX20plmyR0CZv+dqzWlo5839FjA6BlSn6tHvL9O4agifjTarwcj3fRlkHjlvKSGqWiDttmCk2+83ilfHpDLncJ8086k1cQhkGu0nox3cuTHcfNJ0YRJeC/n/fFelL92KV/PSSHjQ/Q5DuzeG5+7a8Y= deploy: provider: npm email: i59naga@icloud.com api_key: - secure: LcnRlhCoHBQSA/noh2latGZeLhgWm3ImcraLo7bx96Xl/b+rCv8Y1txG+OPtWUpVF9Euwan6J3QQpivRgHvSf9pwAY3U0mymHFf1Ho9UIen7pHgB59/JTdPxlAH2U6I4zc/0tXdo1kznKpIjHqo3MqCYWQF2jT9Kupcgcek5sOc= \ No newline at end of file + secure: LcnRlhCoHBQSA/noh2latGZeLhgWm3ImcraLo7bx96Xl/b+rCv8Y1txG+OPtWUpVF9Euwan6J3QQpivRgHvSf9pwAY3U0mymHFf1Ho9UIen7pHgB59/JTdPxlAH2U6I4zc/0tXdo1kznKpIjHqo3MqCYWQF2jT9Kupcgcek5sOc= diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e7d2cf..9ff2955 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ +v0.1.4 / Mar 29 2015 +========================= + * [`unknown`][1] :bug: Fix `` + +[1]: https://github.com/59naga/jaggy/commit + v0.1.3 / Mar 03 2015 ========================= - * [`unknown`][unknown] Release v0.1.3 + * [`unknown`][0] Release v0.1.3 -[unknown]: https:// \ No newline at end of file +[0]: https://github.com/59naga/jaggy/commits/master \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index e6f9e93..0000000 --- a/LICENSE.md +++ /dev/null @@ -1,37 +0,0 @@ -The MIT License (MIT) - ---- - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ---- - -以下に定める条件に従い、本ソフトウェアおよび関連文書のファイル(以下「ソフトウェア」)の複製を取得するすべての人に対し、ソフトウェアを無制限に扱うことを無償で許可します。 -これには、ソフトウェアの複製を使用、複写、変更、結合、掲載、頒布、サブライセンス、および/または販売する権利、およびソフトウェアを提供する相手に同じことを許可する権利も無制限に含まれます。 - -上記の著作権表示および本許諾表示を、ソフトウェアのすべての複製または重要な部分に記載するものとします。 - -ソフトウェアは「現状のまま」で、明示であるか暗黙であるかを問わず、何らの保証もなく提供されます。 -ここでいう保証とは、商品性、特定の目的への適合性、および権利非侵害についての保証も含みますが、それに限定されるものではありません。 -作者または著作権者は、契約行為、不法行為、またはそれ以外であろうと、ソフトウェアに起因または関連し、あるいはソフトウェアの使用またはその他の扱いによって生じる一切の請求、損害、その他の義務について何らの責任も負わないものとします。 - ---- - -Copyright (c) 2015 59naga \ No newline at end of file diff --git a/README.md b/README.md index 28da5fc..2e8f565 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,9 @@ jaggy public_html -g 5 License ========================= -MIT by 59naga +[MIT][License] by 59naga + +[License]: http://59naga.mit-license.org/ [.svg]: https://cdn.rawgit.com/59naga/jaggy/master/.svg? diff --git a/bower.json b/bower.json index 4dea6a3..3edb58e 100644 --- a/bower.json +++ b/bower.json @@ -1,12 +1,12 @@ { "name": "jaggy", - "version": "0.0.7", + "version": "0.1.3", "homepage": "https://github.com/59naga/jaggy", "authors": [ "59naga " ], "description": " to ", - "main": "sources/jaggy.browser.min.js", + "main": "public/jaggy.browser.js", "keywords": [ "pixel", "pixel-art", diff --git a/gulpfile.coffee b/gulpfile.coffee deleted file mode 100644 index dcacd9a..0000000 --- a/gulpfile.coffee +++ /dev/null @@ -1,42 +0,0 @@ -gulp= require 'gulp' - -gulp.task 'default',-> - gulp.start 'test' - watch= require 'gulp-watch' - watch files,-> gulp.start 'test' - - livereload= require 'gulp-connect' - livereload.server - livereload: true - port: 59798 - root: 'public_html' - - gulp.src "public_html/**" - .pipe watch "public_html/**" - .pipe livereload.reload() - -gulp.task 'browserify',(done)-> - source= require 'vinyl-source-stream' - browserify= require 'browserify' - browserify - entries: "./jaggy.coffee" - extensions: '.coffee' - .require 'get-pixels' - .require 'gify-parse' - .exclude 'node_modules/**' - .transform 'coffeeify' - .bundle() - .pipe source 'jaggy.browser.js' - .pipe gulp.dest 'sources' - .on 'end',-> - filename= 'sources/jaggy.browser.js' - mainfile= 'sources/jaggy.browser.min.js' - script= "cp #{filename} #{mainfile}" - script= "node_modules/.bin/uglifyjs #{filename} > #{mainfile}" if '-min' in process.argv - - exec= require('child_process').exec - exec script,()-> - fs= require 'fs' - fs.unlinkSync filename - done() - return \ No newline at end of file diff --git a/jaggy b/jaggy index 08be9aa..8c17def 100644 --- a/jaggy +++ b/jaggy @@ -1,3 +1,18 @@ #!/usr/bin/env node -require('./').cli(); \ No newline at end of file +if(typeof require('module')._extensions['.coffee']==='undefined'){ + // Avoid conflicts with another version + require('coffee-script/register'); +} +var jaggy= require('./lib/jaggy.coffee'); + +if(module.parent===null){ + process.on('uncaughtException',function(error){ + throw error; + process.exit(1); + }); + + jaggy.cli(process.argv.slice(2)); +} + +module.exports= jaggy; \ No newline at end of file diff --git a/jaggy.coffee b/jaggy.coffee deleted file mode 100644 index d400faa..0000000 --- a/jaggy.coffee +++ /dev/null @@ -1,360 +0,0 @@ -Jaggy= -> - Jaggy.createSVG.apply null,arguments if typeof window isnt 'undefined' - Jaggy.gulpPlugin.apply null,arguments if typeof window is 'undefined' - -Jaggy.cli= -> - commander= require 'commander' - commander - .version require('./package.json').version - .usage 'file/directory [options...]' - .option '-r recursive','Convert pixelarts in recursive directory' - .option '-o output ','Output directory <./>','.' - .option '-g --glitch ','Glitch color palettes <4>',4 - .parse process.argv - commander.help() if commander.args.length is 0 - - path= require 'path' - globs= [] - for arg in commander.args - if arg.match(/(\.gif|\.jpg|\.png)$/) - glob= path.resolve arg - else - glob= path.resolve "#{arg}/*.+(gif|png|jpg)" - glob= path.resolve "#{arg}/**/*.+(gif|png|jpg)" if commander.recursive - globs.push glob - globs.push '!**/*.!(*gif|*png|*jpg)' # Ignore unsupport extension - - gulp= require 'gulp' - gulp.src globs,base:process.cwd() - .pipe Jaggy.gulpPlugin glitch:commander.glitch - .pipe gulp.dest path.resolve commander.output - .on 'data',(file)-> console.log 'Convert',path.relative process.cwd(),file.path.replace(/(\.gif|\.jpg|\.png)$/,'.svg') - .on 'end',-> - process.exit() - -Jaggy.gulpPlugin= (options={})-> - gutil= require 'gulp-util' - through2= require 'through2' - return through2.obj (file,encode,next)-> - return @emit 'error',new gutil.PluginError 'jaggy','Streaming not supported' if file.isStream() - - Jaggy.readImageData file,(error,pixels)=> - throw error if error? - - Jaggy.convertToSVG pixels,options,(error,svg)=> - throw error if error? - - file.path= gutil.replaceExtension file.path,'.svg' - file.contents= new Buffer svg - @push file - - next() - -# Use url for browser -Jaggy.createSVG= (url,args...)-> - throw new Error 'url is not string' if typeof url isnt 'string' - callback= null - options= {} - args.forEach (arg)-> switch typeof arg - when 'function' then callback= arg - when 'object' then options= arg - options.outerHTML?= false - - getPixels= require 'get-pixels' - getPixels url,(error,pixels)-> - return callback error if error? - - if pixels.shape.length is 3 - Jaggy.convertToSVG pixels,options,callback - - if pixels.shape.length is 4 - xhr= new XMLHttpRequest - xhr.open 'GET',url,true - xhr.responseType= 'arraybuffer' - xhr.send() - xhr.onerror= -> callback xhr.statusText - xhr.onload= -> - gifyParse= require 'gify-parse' - anime= gifyParse.getInfo xhr.response - anime.delays= anime.images.map (image)-> image.delay - anime.disposals= anime.images.map (image)-> image.disposal - pixels.anime= anime - - Jaggy.convertToSVG pixels,options,callback - -# Use for angular.js -Jaggy.angularModule= (window)-> - angularModule= window.angular.module 'jaggy',[] - angularModule.directive 'jaggy',-> - (scope,element,attrs)-> - element.css 'display','none' - - options= {} - if attrs.jaggy - for param in attrs.jaggy.split ';' - [key,value]= param.split ':' - options[key]= value - - Jaggy.createSVG attrs.src,options,(error,svg)-> - throw error if error? - element.replaceWith svg - -Jaggy.convertToSVG= (pixels,args...)-> - callback= null - options= {} - args.forEach (arg)-> switch typeof arg - when 'function' then callback= arg - when 'object' then options= arg - options.glitch= +options.glitch if typeof options.glitch is 'string' - return callback new Error('glitch is 0') if options.glitch is 0 - - jaggy= Jaggy.convert pixels,options - - svg= jaggy.toSVG options - svg= options.afterConvert svg,jaggy,file if typeof options.afterConvert is 'function' - - if options.outerHTML isnt false - svg= svg.outerHTML.replace ' viewbox=',' viewBox='# fix to lowerCamel - svg= svg.replace(/>/g,'>')# enable querySelector - - callback null,svg - -Jaggy.enableAnimation= (svg)-> - throw new Error('Can enable appended element only') if svg.parentNode is null - - # fix disabled script - script= svg.querySelector 'script' - script.parentNode.replaceChild script.cloneNode(),script - svg - -# Use Buffer for node.js -Jaggy.readImageData= (file,callback)-> - return callback 'file is not object' if typeof file isnt 'object' - - buffer= new Buffer file.contents - - mime= require 'mime' - mimeType= mime.lookup file.path - - getPixels= require 'get-pixels' - getPixels buffer,mimeType,(error,pixels)-> - return callback error if error? - - if pixels.shape.length is 4 - gifyParse= require 'gify-parse' - anime= gifyParse.getInfo buffer - anime.delays= anime.images.map (image)-> image.delay - anime.disposals= anime.images.map (image)-> image.disposal - pixels.anime= anime - - callback null,pixels - -Jaggy.convert= (pixels,options={})-> - throw new Error 'Not supported File' if pixels?.shape?.length is undefined - - [width,height,channel]= pixels.shape if pixels.shape.length is 3 - [frame,width,height,channel]= pixels.shape if pixels.shape.length is 4 - pixels.frame= frame ? 1 - pixels.width= width - pixels.height= height - pixels.channel= channel - - new Jaggy.Frames pixels,options - -class Jaggy.Frames - constructor:(image,options={})-> - @attrs= - 'version': '1.1' - 'xmlns': 'http://www.w3.org/2000/svg' - 'xmlns:xlink': 'http://www.w3.org/1999/xlink' - - 'shape-rendering': 'crispEdges' - 'width': image.width - 'height': image.height - 'viewBox': "0 0 #{image.width} #{image.height}" - - @frame_size= image.width*image.height*image.channel - @frames= [] - @delays= image.anime || [] - - i= 0 - while image.data[i*@frame_size] isnt undefined - frame= new Jaggy.Frame - frame.delay= image.anime.delays[i] if image.anime? - frame.disposal= image.anime.disposals[i] if image.anime? - frame.putImageData i*@frame_size,i*@frame_size+@frame_size,image,options - @frames.push frame - - i++ - - toSVG:-> - svg= Jaggy.createElementNS 'svg' - for key,value of @attrs - svg.setAttribute key,value if key.indexOf('xmlns') is 0 - svg.setAttributeNS null,key,value if key.indexOf('xmlns') isnt 0 - if @frames.length is 1 - svg.appendChild @frames[0].toG() - else - svg.setAttribute 'id','A'+uuid() - svg.appendChild @createAnime() - svg.appendChild @createScript(svg.id) - svg - - createAnime:-> - g= Jaggy.createElementNS 'g' - g.setAttribute 'style','display:none' - g.appendChild frame.toG() for frame in @frames - g - - createScript:(id)-> - script= Jaggy.createElement 'script' - script.appendChild Jaggy.createTextNode "(#{animation.toString()})('#{id}');" - script - - # private - - animation= (id)-> - i= 0 - frames= [].slice.call document.querySelectorAll '#'+id+'>g>g' - display= null - - setTimeout -> nextFrame() - nextFrame=-> - frame= frames[i] - frame= frames[i= 0] if frame is undefined - frame_id= frame.getAttribute 'id' - if frame_id is null - frame_id= id+'_'+('0000'+i).slice(-5) - frame.setAttribute 'id',frame_id - - if i is 0 - uses= document.querySelectorAll '#'+id+'>use' - use.parentNode.removeChild use for use in uses - - i++ - createDisplay frame_id - setTimeout nextFrame,frame.getAttribute 'delay' - - createDisplay=(frame_id)-> - display= document.createElementNS 'http://www.w3.org/2000/svg','use' - display.setAttributeNS 'http://www.w3.org/1999/xlink','href','#'+frame_id if frame_id - document.querySelector('#'+id).insertBefore display,document.querySelector '#'+id+'>g' - - uuid= -> - # via http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript - S4=-> (((1+Math.random())*0x10000)|0).toString(16).substring(1) - S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4() - -class Jaggy.Frame# has many Color - constructor:-> - putImageData:(begin,end,image,options={})-> - for key,value of this - delete this[key] if this.hasOwnProperty key and key isnt 'attrs' - - return if image.data is undefined - - i= 0 - increment= if options.glitch? then options.glitch else 4 - while (begin+i) <= end - # if @disposal is 3 - # values.push image.data[i+0] - # values.push image.data[i+1] - # values.push image.data[i+2] - # values.push (image.data[i+3]/255).toFixed(2) - - if image.data[begin+i+3] isnt 0 - values= [] - values.push image.data[begin+i+0] - values.push image.data[begin+i+1] - values.push image.data[begin+i+2] - values.push (image.data[begin+i+3]/255).toFixed(2) - - rgba= 'rgba('+values.join(',')+')' - if this[rgba] is undefined - this[rgba]= new Jaggy.Color - - x= (i/4)% image.width - y= ~~((i/4)/image.width) - this[rgba].put (new Jaggy.Point x,y) - - i= if typeof increment is 'function' then increment(i) else i+increment - - toG:-> - g= Jaggy.createElementNS 'g' - for key,value of this - g.setAttribute key,value if typeof value is 'number' - g.appendChild value.toPath key if value instanceof Jaggy.Color - g - -class Jaggy.Color# has many Rect in @points - constructor:(@points=[])-> - put:(point)-> @points.push point - - toPath:(fill='black')-> - path= Jaggy.createElementNS 'path' - path.setAttributeNS null,'fill',fill if fill.length - path.setAttributeNS null, 'd',@getRects().map((rect)->rect.toD()).join '' if @points.length - path - - getRects:-> - rects= [] - - # Merge @points for horizontal - rect_index= {}# Merge to rect of over if equal x and width - i= 0 - while i < @points.length - point= @points[i++] - - left= rects[rects.length-1]|| {} - is_left= left.y is point.y and (left.x+left.width) is point.x - if is_left - left.width++ - continue - - rect_index[left.x]?= {} - rect_index[left.x][left.y]= left if left.width - left_over= rect_index[left.x][left.y-1] || {} - is_same_length= left.width is left_over.width and left_over.x isnt undefined - if is_same_length - left_over.height++# Glitch point... - rect_index[left.x][left.y]= left_over - rects.pop() - i-- - continue - - rects.push point.toRect() - - rects - -class Jaggy.Rect - constructor:(point)-> - @x= point.x - @y= point.y - @width= 1 - @height= 1 - - toD: -> - # 1pixel = - 'M'+@x+','+@y+'h'+@width+'v'+@height+'h-'+@width+'Z'; - -class Jaggy.Point - constructor:(@x,@y)-> - toRect:-> new Jaggy.Rect this - -if typeof window isnt 'undefined' - Jaggy.createElement= document.createElement.bind document - Jaggy.createElementNS= document.createElementNS.bind document,'http://www.w3.org/2000/svg' - Jaggy.createTextNode= document.createTextNode.bind document - - window.jaggy= Jaggy - Jaggy.angularModule window if typeof window.angular is 'object' -else - domlite= require('dom-lite').document - Jaggy.createElement= domlite.createElement.bind domlite - Jaggy.createElementNS= (name)-> - element= Jaggy.createElement name - element.setAttributeNS?= (ns,key,value)-> this.setAttribute key,value - element - Jaggy.createTextNode= domlite.createTextNode.bind domlite - - module.exports= Jaggy if typeof window is 'undefined' \ No newline at end of file diff --git a/jaggy.pomace.js b/jaggy.pomace.js deleted file mode 100644 index c0526b0..0000000 --- a/jaggy.pomace.js +++ /dev/null @@ -1,5 +0,0 @@ -// Avoid conflicts with another version -if(typeof require('module')._extensions['.coffee']==='undefined'){ - require('coffee-script/register'); -} -module.exports= require('./jaggy.coffee'); \ No newline at end of file diff --git a/jaggy.spec.coffee b/jaggy.spec.coffee deleted file mode 100644 index 803321d..0000000 --- a/jaggy.spec.coffee +++ /dev/null @@ -1,76 +0,0 @@ -Jaggy= require './' -gulp= require 'gulp' - -jasmine.DEFAULT_TIMEOUT_INTERVAL= 10000 - -describe 'Jaggy',-> - describe 'Standard Usage',-> - it 'Convert to by .gif',(done)-> - gulp.src 'public_html/*.gif' - .pipe Jaggy() - .pipe gulp.dest 'public_html' - .on 'end',done - - it 'Convert to by .png',(done)-> - gulp.src 'public_html/*.png' - .pipe Jaggy() - .pipe gulp.dest 'public_html' - .on 'end',done - - it 'Convert to by .jpg',(done)-> - gulp.src 'public_html/*.jpg' - .pipe Jaggy() - .pipe gulp.dest 'public_html' - .on 'end',-> - done() - - it 'Glitch to by .png',(done)-> - gulp.src 'public_html/yuno.png' - .pipe Jaggy glitch:3 - .pipe gulp.dest 'public_html' - .on 'end',done - - it 'Convert to pixels by gutil.File',(done)-> - gutil= require 'gulp-util' - path= require 'path' - fs= require 'fs' - - file= new gutil.File - cwd: __dirname - base: "#{__dirname}/public_html/" - path: "#{__dirname}/public_html/moon.png" - contents: fs.readFileSync "#{__dirname}/public_html/moon.png" - - Jaggy.readImageData file,(error,pixels)-> - expect(error).toEqual(null) - expect(pixels.data.length).toEqual(96*192*4) - expect(JSON.stringify pixels.shape).toEqual('[96,192,4]') - - done() - - describe 'Create Element',-> - it 'Convert to by Frame',-> - frame= new Jaggy.Frame - expect(frame.toG().outerHTML).toEqual('') - - it 'Convert to by Color',-> - color= new Jaggy.Color - expect(color.toPath('').outerHTML).toEqual('') - - describe 'Class',-> - it 'Color has points',-> - color= new Jaggy.Color - expect(JSON.stringify color).toEqual('{"points":[]}') - - it 'Point is {x,y}',-> - point= new Jaggy.Point 0,0 - expect(JSON.stringify point).toEqual('{"x":0,"y":0}') - - it 'Rect like a Point ',-> - point= new Jaggy.Point 0,0 - rect= new Jaggy.Rect point - expect(JSON.stringify rect).toMatch((JSON.stringify point).slice(-1)) - - it 'Rect is M0,0h1v1h-1Z',-> - rect= new Jaggy.Rect x:0,y:0 - expect(rect.toD()).toEqual('M0,0h1v1h-1Z') \ No newline at end of file diff --git a/lib/classes.coffee b/lib/classes.coffee new file mode 100644 index 0000000..b0443f8 --- /dev/null +++ b/lib/classes.coffee @@ -0,0 +1,188 @@ +if typeof window isnt 'undefined' + createElement= document.createElement.bind document + createElementNS= document.createElementNS.bind document,'http://www.w3.org/2000/svg' + createTextNode= document.createTextNode.bind document +else + domlite= require('dom-lite').document + createElement= domlite.createElement.bind domlite + createElementNS= (name)-> + element= createElement name + element.setAttributeNS?= (ns,key,value)-> this.setAttribute key,value + element + createTextNode= domlite.createTextNode.bind domlite + +class Frames + constructor:(image,options={})-> + @attrs= + 'version': '1.1' + 'xmlns': 'http://www.w3.org/2000/svg' + 'xmlns:xlink': 'http://www.w3.org/1999/xlink' + + 'shape-rendering': 'crispEdges' + 'width': image.width + 'height': image.height + 'viewBox': "0 0 #{image.width} #{image.height}" + + @frame_size= image.width*image.height*image.channel + @frames= [] + @delays= image.anime || [] + + i= 0 + while image.data[i*@frame_size] isnt undefined + frame= new Frame + frame.delay= image.anime.delays[i] if image.anime? + frame.disposal= image.anime.disposals[i] if image.anime? + frame.putImageData i*@frame_size,i*@frame_size+@frame_size,image,options + @frames.push frame + + i++ + + toSVG:-> + svg= createElementNS 'svg' + for key,value of @attrs + svg.setAttribute key,value if key.indexOf('xmlns') is 0 + svg.setAttributeNS null,key,value if key.indexOf('xmlns') isnt 0 + if @frames.length is 1 + svg.appendChild @frames[0].toG() + else + svg.setAttribute 'id','A'+uuid() + svg.appendChild @createAnime() + svg.appendChild @createScript(svg.id) + svg + + createAnime:-> + g= createElementNS 'g' + g.setAttribute 'style','display:none' + g.appendChild frame.toG() for frame in @frames + g + + createScript:(id)-> + script= createElement 'script' + script.appendChild createTextNode "(#{animation.toString()})('#{id}');" + script + + # private + + animation= (id)-> + i= 0 + frames= [].slice.call document.querySelectorAll '#'+id+'>g>g' + display= null + + setTimeout -> nextFrame() + nextFrame=-> + frame= frames[i] + frame= frames[i= 0] if frame is undefined + frame_id= frame.getAttribute 'id' + if frame_id is null + frame_id= id+'_'+('0000'+i).slice(-5) + frame.setAttribute 'id',frame_id + + if i is 0 + uses= document.querySelectorAll '#'+id+'>use' + use.parentNode.removeChild use for use in uses + + i++ + createDisplay frame_id + setTimeout nextFrame,frame.getAttribute 'delay' + + createDisplay=(frame_id)-> + display= document.createElementNS 'http://www.w3.org/2000/svg','use' + display.setAttributeNS 'http://www.w3.org/1999/xlink','href','#'+frame_id if frame_id + document.querySelector('#'+id).insertBefore display,document.querySelector '#'+id+'>g' + + uuid= -> + # via http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript + S4=-> (((1+Math.random())*0x10000)|0).toString(16).substring(1) + S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4() + +class Frame# has many Color + constructor:-> + putImageData:(begin,end,image,options={})-> + for key,value of this + delete this[key] if this.hasOwnProperty key and key isnt 'attrs' + + return if image.data is undefined + + i= 0 + increment= if options.glitch? then options.glitch else 4 + while (begin+i) <= end + opacity= image.data[begin+i+3] > 0 and image.data[begin+i+0]? + if opacity + values= [] + values.push image.data[begin+i+0] + values.push image.data[begin+i+1] + values.push image.data[begin+i+2] + values.push (image.data[begin+i+3]/255).toFixed(2) + + x= (i/4)% image.width + y= ~~((i/4)/image.width) + + rgba= 'rgba('+values.join(',')+')' + @[rgba]= new Color if not @[rgba]? + @[rgba].put (new Point x,y) + + i= if typeof increment is 'function' then increment(i) else i+increment + + toG:-> + g= createElementNS 'g' + for key,value of this + g.setAttribute key,value if typeof value is 'number' + g.appendChild value.toPath key if value instanceof Color + g + +class Color# has many Rect in @points + constructor:(@points=[])-> + put:(point)-> @points.push point + + toPath:(fill='black')-> + path= createElementNS 'path' + path.setAttributeNS null,'fill',fill if fill.length + path.setAttributeNS null, 'd',@getRects().map((rect)->rect.toD()).join '' if @points.length + path + + getRects:-> + rects= [] + + # Merge @points for horizontal + rect_index= {}# Merge to rect of over if equal x and width + i= 0 + while i < @points.length + point= @points[i++] + + left= rects[rects.length-1]|| {} + is_left= left.y is point.y and (left.x+left.width) is point.x + if is_left + left.width++ + continue + + rect_index[left.x]?= {} + rect_index[left.x][left.y]= left if left.width + left_over= rect_index[left.x][left.y-1] || {} + is_same_length= left.width is left_over.width and left_over.x isnt undefined + if is_same_length + left_over.height++# Glitch point... + rect_index[left.x][left.y]= left_over + rects.pop() + i-- + continue + + rects.push point.toRect() + + rects + +class Rect + constructor:(point)-> + @x= point.x + @y= point.y + @width= 1 + @height= 1 + + toD: -> + # 1pixel = + 'M'+@x+','+@y+'h'+@width+'v'+@height+'h-'+@width+'Z'; + +class Point + constructor:(@x,@y)-> + toRect:-> new Rect this + +module.exports= {Frames, Frame, Color, Rect, Point} \ No newline at end of file diff --git a/lib/jaggy.coffee b/lib/jaggy.coffee new file mode 100644 index 0000000..1c82bcc --- /dev/null +++ b/lib/jaggy.coffee @@ -0,0 +1,173 @@ +Jaggy= -> + Jaggy.createSVG.apply null,arguments if typeof window isnt 'undefined' + Jaggy.gulpPlugin.apply null,arguments if typeof window is 'undefined' + +Jaggy.cli= -> + cli= new (require 'commander').Command + cli + .version require('../package.json').version + .usage 'file/directory [options...]' + .option '-r recursive','Convert pixelarts in recursive directory' + .option '-o output ','Output directory <./>','.' + .option '-g --glitch ','Glitch color palettes <4>',4 + .parse process.argv + cli.help() if cli.args.length is 0 + + path= require 'path' + globs= [] + for arg in cli.args + if arg.match(/(\.gif|\.jpg|\.png)$/) + glob= path.resolve arg + else + glob= path.resolve "#{arg}/*.+(gif|png|jpg)" + glob= path.resolve "#{arg}/**/*.+(gif|png|jpg)" if cli.recursive + globs.push glob + globs.push '!**/*.!(*gif|*png|*jpg)' # Ignore unsupport extension + + gulp= require 'gulp' + gulp.src globs,base:process.cwd() + .pipe Jaggy.gulpPlugin glitch:cli.glitch + .pipe gulp.dest path.resolve cli.output + .on 'data',(file)-> console.log 'Convert',path.relative process.cwd(),file.path.replace(/(\.gif|\.jpg|\.png)$/,'.svg') + .on 'end',-> + process.exit() + +Jaggy.gulpPlugin= (options={})-> + gutil= require 'gulp-util' + through2= require 'through2' + return through2.obj (file,encode,next)-> + return @emit 'error',new gutil.PluginError 'jaggy','Streaming not supported' if file.isStream() + + Jaggy.readImageData file,(error,pixels)=> + throw error if error? + + Jaggy.convertToSVG pixels,options,(error,svg)=> + throw error if error? + + file.path= gutil.replaceExtension file.path,'.svg' + file.contents= new Buffer svg + @push file + + next() + +# Use url for browser +Jaggy.createSVG= (url,args...)-> + throw new Error 'url is not string' if typeof url isnt 'string' + callback= null + options= {} + args.forEach (arg)-> switch typeof arg + when 'function' then callback= arg + when 'object' then options= arg + options.outerHTML?= false + + getPixels= require 'get-pixels' + getPixels url,(error,pixels)-> + return callback error if error? + + if pixels.shape.length is 3 + Jaggy.convertToSVG pixels,options,callback + + if pixels.shape.length is 4 + xhr= new XMLHttpRequest + xhr.open 'GET',url,true + xhr.responseType= 'arraybuffer' + xhr.send() + xhr.onerror= -> callback xhr.statusText + xhr.onload= -> + gifyParse= require 'gify-parse' + anime= gifyParse.getInfo xhr.response + anime.delays= anime.images.map (image)-> image.delay + anime.disposals= anime.images.map (image)-> image.disposal + pixels.anime= anime + + Jaggy.convertToSVG pixels,options,callback + +# Use for angular.js +Jaggy.angularModule= (window)-> + angularModule= window.angular.module 'jaggy',[] + angularModule.directive 'jaggy',-> + (scope,element,attrs)-> + element.css 'display','none' + + options= {} + if attrs.jaggy + for param in attrs.jaggy.split ';' + [key,value]= param.split ':' + options[key]= value + + #fix + url= attrs.src + url?= attrs.ngSrc + + Jaggy.createSVG url,options,(error,svg)-> + throw error if error? + element.replaceWith svg + +Jaggy.convertToSVG= (pixels,args...)-> + callback= null + options= {} + args.forEach (arg)-> switch typeof arg + when 'function' then callback= arg + when 'object' then options= arg + options.glitch= +options.glitch if typeof options.glitch is 'string' + return callback new Error('glitch is 0') if options.glitch is 0 + + jaggy= Jaggy.convert pixels,options + + svg= jaggy.toSVG options + svg= options.afterConvert svg,jaggy,file if typeof options.afterConvert is 'function' + + if options.outerHTML isnt false + svg= svg.outerHTML.replace ' viewbox=',' viewBox='# fix to lowerCamel + svg= svg.replace(/>/g,'>')# enable querySelector + + callback null,svg + +Jaggy.enableAnimation= (svg)-> + throw new Error('Can enable appended element only') if svg.parentNode is null + + # fix disabled script + script= svg.querySelector 'script' + script.parentNode.replaceChild script.cloneNode(),script + svg + +# Use Buffer for node.js +Jaggy.readImageData= (file,callback)-> + return callback 'file is not object' if typeof file isnt 'object' + + buffer= new Buffer file.contents + + mime= require 'mime' + mimeType= mime.lookup file.path + + getPixels= require 'get-pixels' + getPixels buffer,mimeType,(error,pixels)-> + return callback error if error? + + if pixels.shape.length is 4 + gifyParse= require 'gify-parse' + anime= gifyParse.getInfo buffer + anime.delays= anime.images.map (image)-> image.delay + anime.disposals= anime.images.map (image)-> image.disposal + pixels.anime= anime + + callback null,pixels + +Jaggy.convert= (pixels,options={})-> + throw new Error 'Not supported File' if pixels?.shape?.length is undefined + + [width,height,channel]= pixels.shape if pixels.shape.length is 3 + [frame,width,height,channel]= pixels.shape if pixels.shape.length is 4 + pixels.frame= frame ? 1 + pixels.width= width + pixels.height= height + pixels.channel= channel + + Frames= (require './classes.coffee').Frames + new Frames pixels,options + +if typeof window isnt 'undefined' + window.jaggy= Jaggy + Jaggy.angularModule window if typeof window.angular is 'object' +else + module.exports= Jaggy if typeof window is 'undefined' \ No newline at end of file diff --git a/package.json b/package.json index a07e8af..085bb98 100644 --- a/package.json +++ b/package.json @@ -1,32 +1,32 @@ { "name": "jaggy", - "bin" : "jaggy", - "main": "jaggy.pomace.js", + "main": "jaggy", + "bin": "jaggy", "description": "is Converting to SVG by pixels", "version": "0.1.3", "scripts": { - "build":"npm run build-nodejs && npm run build-browser", - "build-nodejs":"npm run pretest", - "build-browser":"gulp browserify -min", + "build": "browserify lib/jaggy.coffee -r get-pixels -r gify-parse -t coffeeify > public/jaggy.browser.js", - "start":"jaggy public_html -o hogekosan -g 2", - "preview": "gulp browserify && open 'http://localhost:8000/public_html/' && python -m SimpleHTTPServer", - - "pretest": "rm -rf node_modules/ibrik/node_modules/coffee-script", - "test": "ibrik cover jasminetea -- . -v && istanbul report html", - "coveralls": "coveralls < ./coverage/lcov.info && rm -rf coverage", + "prestart": "onefile --json --output public/pkgs", + "start": "cd public && open http://localhost:8000 && python -m SimpleHTTPServer", - "lint": "jasminetea . -l \"*.coffee,!*.spec.coffee\"", - "clean": "rm public_html/*.svg" + "convert": "jaggy public -o hogekosan -g 2", + + "test": "jasminetea test --verbose --cover --report", + "posttest": "rm public/*.svg", + + "prepublish": "npm run build", + "publish": "npm publish" }, + "dependencies": { + "browserify": "^9.0.3", "coffee-script": "^1.9.0", "commander": "^2.6.0", - "dom-lite": "^0.3.8", + "dom-lite": "^0.4.0", "get-pixels": "^3.1.0", "gify-parse": "^1.0.4", - "gulp": "^3.8.10", "gulp-util": "^3.0.3", "mime": "^1.2.11", "through2": "^0.6.3" @@ -34,17 +34,8 @@ "devDependencies": { "browserify": "^8.1.3", "coffeeify": "^1.0.0", - "coveralls": "^2.11.2", - "gulp-connect": "^2.2.0", - "gulp-jasmine": "^2.0.0", - "gulp-watch": "^4.1.0", - "uglify-js": "^2.4.16", - "vinyl-source-stream": "^1.0.0", - "ibrik": "^2.0.0", - "istanbul": "^0.3.6", - "jasminetea": "^0.1.4" + "jasminetea": "^0.1.27" }, - "keywords": [ "pixelart", "get-pixels", diff --git a/public_html/chrono_trigger.jpg b/public/chrono_trigger.jpg similarity index 100% rename from public_html/chrono_trigger.jpg rename to public/chrono_trigger.jpg diff --git a/public_html/index.html b/public/index.html similarity index 89% rename from public_html/index.html rename to public/index.html index 293cde4..8ba2ae3 100644 --- a/public_html/index.html +++ b/public/index.html @@ -3,8 +3,8 @@ Document - - + +