├── FileSaver.js ├── README.md ├── canvasthumber.js ├── index.html ├── jszip.min.js └── styles.css /FileSaver.js: -------------------------------------------------------------------------------- 1 | /*! FileSaver.js 2 | * A saveAs() FileSaver implementation. 3 | * 2014-01-24 4 | * 5 | * By Eli Grey, http://eligrey.com 6 | * License: X11/MIT 7 | * See LICENSE.md 8 | */ 9 | 10 | /*global self */ 11 | /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ 12 | 13 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 14 | 15 | var saveAs = saveAs 16 | // IE 10+ (native saveAs) 17 | || (typeof navigator !== "undefined" && 18 | navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) 19 | // Everyone else 20 | || (function(view) { 21 | "use strict"; 22 | // IE <10 is explicitly unsupported 23 | if (typeof navigator !== "undefined" && 24 | /MSIE [1-9]\./.test(navigator.userAgent)) { 25 | return; 26 | } 27 | var 28 | doc = view.document 29 | // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet 30 | , get_URL = function() { 31 | return view.URL || view.webkitURL || view; 32 | } 33 | , URL = view.URL || view.webkitURL || view 34 | , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") 35 | , can_use_save_link = !view.externalHost && "download" in save_link 36 | , click = function(node) { 37 | var event = doc.createEvent("MouseEvents"); 38 | event.initMouseEvent( 39 | "click", true, false, view, 0, 0, 0, 0, 0 40 | , false, false, false, false, 0, null 41 | ); 42 | node.dispatchEvent(event); 43 | } 44 | , webkit_req_fs = view.webkitRequestFileSystem 45 | , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem 46 | , throw_outside = function(ex) { 47 | (view.setImmediate || view.setTimeout)(function() { 48 | throw ex; 49 | }, 0); 50 | } 51 | , force_saveable_type = "application/octet-stream" 52 | , fs_min_size = 0 53 | , deletion_queue = [] 54 | , process_deletion_queue = function() { 55 | var i = deletion_queue.length; 56 | while (i--) { 57 | var file = deletion_queue[i]; 58 | if (typeof file === "string") { // file is an object URL 59 | URL.revokeObjectURL(file); 60 | } else { // file is a File 61 | file.remove(); 62 | } 63 | } 64 | deletion_queue.length = 0; // clear queue 65 | } 66 | , dispatch = function(filesaver, event_types, event) { 67 | event_types = [].concat(event_types); 68 | var i = event_types.length; 69 | while (i--) { 70 | var listener = filesaver["on" + event_types[i]]; 71 | if (typeof listener === "function") { 72 | try { 73 | listener.call(filesaver, event || filesaver); 74 | } catch (ex) { 75 | throw_outside(ex); 76 | } 77 | } 78 | } 79 | } 80 | , FileSaver = function(blob, name) { 81 | // First try a.download, then web filesystem, then object URLs 82 | var 83 | filesaver = this 84 | , type = blob.type 85 | , blob_changed = false 86 | , object_url 87 | , target_view 88 | , get_object_url = function() { 89 | var object_url = get_URL().createObjectURL(blob); 90 | deletion_queue.push(object_url); 91 | return object_url; 92 | } 93 | , dispatch_all = function() { 94 | dispatch(filesaver, "writestart progress write writeend".split(" ")); 95 | } 96 | // on any filesys errors revert to saving with object URLs 97 | , fs_error = function() { 98 | // don't create more object URLs than needed 99 | if (blob_changed || !object_url) { 100 | object_url = get_object_url(blob); 101 | } 102 | if (target_view) { 103 | target_view.location.href = object_url; 104 | } else { 105 | window.open(object_url, "_blank"); 106 | } 107 | filesaver.readyState = filesaver.DONE; 108 | dispatch_all(); 109 | } 110 | , abortable = function(func) { 111 | return function() { 112 | if (filesaver.readyState !== filesaver.DONE) { 113 | return func.apply(this, arguments); 114 | } 115 | }; 116 | } 117 | , create_if_not_found = {create: true, exclusive: false} 118 | , slice 119 | ; 120 | filesaver.readyState = filesaver.INIT; 121 | if (!name) { 122 | name = "download"; 123 | } 124 | if (can_use_save_link) { 125 | object_url = get_object_url(blob); 126 | // FF for Android has a nasty garbage collection mechanism 127 | // that turns all objects that are not pure javascript into 'deadObject' 128 | // this means `doc` and `save_link` are unusable and need to be recreated 129 | // `view` is usable though: 130 | doc = view.document; 131 | save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"); 132 | save_link.href = object_url; 133 | save_link.download = name; 134 | var event = doc.createEvent("MouseEvents"); 135 | event.initMouseEvent( 136 | "click", true, false, view, 0, 0, 0, 0, 0 137 | , false, false, false, false, 0, null 138 | ); 139 | save_link.dispatchEvent(event); 140 | filesaver.readyState = filesaver.DONE; 141 | dispatch_all(); 142 | return; 143 | } 144 | // Object and web filesystem URLs have a problem saving in Google Chrome when 145 | // viewed in a tab, so I force save with application/octet-stream 146 | // http://code.google.com/p/chromium/issues/detail?id=91158 147 | if (view.chrome && type && type !== force_saveable_type) { 148 | slice = blob.slice || blob.webkitSlice; 149 | blob = slice.call(blob, 0, blob.size, force_saveable_type); 150 | blob_changed = true; 151 | } 152 | // Since I can't be sure that the guessed media type will trigger a download 153 | // in WebKit, I append .download to the filename. 154 | // https://bugs.webkit.org/show_bug.cgi?id=65440 155 | if (webkit_req_fs && name !== "download") { 156 | name += ".download"; 157 | } 158 | if (type === force_saveable_type || webkit_req_fs) { 159 | target_view = view; 160 | } 161 | if (!req_fs) { 162 | fs_error(); 163 | return; 164 | } 165 | fs_min_size += blob.size; 166 | req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { 167 | fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { 168 | var save = function() { 169 | dir.getFile(name, create_if_not_found, abortable(function(file) { 170 | file.createWriter(abortable(function(writer) { 171 | writer.onwriteend = function(event) { 172 | target_view.location.href = file.toURL(); 173 | deletion_queue.push(file); 174 | filesaver.readyState = filesaver.DONE; 175 | dispatch(filesaver, "writeend", event); 176 | }; 177 | writer.onerror = function() { 178 | var error = writer.error; 179 | if (error.code !== error.ABORT_ERR) { 180 | fs_error(); 181 | } 182 | }; 183 | "writestart progress write abort".split(" ").forEach(function(event) { 184 | writer["on" + event] = filesaver["on" + event]; 185 | }); 186 | writer.write(blob); 187 | filesaver.abort = function() { 188 | writer.abort(); 189 | filesaver.readyState = filesaver.DONE; 190 | }; 191 | filesaver.readyState = filesaver.WRITING; 192 | }), fs_error); 193 | }), fs_error); 194 | }; 195 | dir.getFile(name, {create: false}, abortable(function(file) { 196 | // delete file if it already exists 197 | file.remove(); 198 | save(); 199 | }), abortable(function(ex) { 200 | if (ex.code === ex.NOT_FOUND_ERR) { 201 | save(); 202 | } else { 203 | fs_error(); 204 | } 205 | })); 206 | }), fs_error); 207 | }), fs_error); 208 | } 209 | , FS_proto = FileSaver.prototype 210 | , saveAs = function(blob, name) { 211 | return new FileSaver(blob, name); 212 | } 213 | ; 214 | FS_proto.abort = function() { 215 | var filesaver = this; 216 | filesaver.readyState = filesaver.DONE; 217 | dispatch(filesaver, "abort"); 218 | }; 219 | FS_proto.readyState = FS_proto.INIT = 0; 220 | FS_proto.WRITING = 1; 221 | FS_proto.DONE = 2; 222 | 223 | FS_proto.error = 224 | FS_proto.onwritestart = 225 | FS_proto.onprogress = 226 | FS_proto.onwrite = 227 | FS_proto.onabort = 228 | FS_proto.onerror = 229 | FS_proto.onwriteend = 230 | null; 231 | 232 | view.addEventListener("unload", process_deletion_queue, false); 233 | saveAs.unload = function() { 234 | process_deletion_queue(); 235 | view.removeEventListener("unload", process_deletion_queue, false); 236 | }; 237 | return saveAs; 238 | }( 239 | typeof self !== "undefined" && self 240 | || typeof window !== "undefined" && window 241 | || this.content 242 | )); 243 | // `self` is undefined in Firefox for Android content script context 244 | // while `this` is nsIContentFrameMessageManager 245 | // with an attribute `content` that corresponds to the window 246 | 247 | if (typeof module !== "undefined") module.exports = saveAs; 248 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Canvas Thumber 2 | 3 | Creates a set of thumbnails from a set of dropped image, downloadable as a zip. 4 | 5 | ## Demo 6 | 7 | You can check the github pages version: https://codepo8.github.io/canvasthumber/ 8 | 9 | And there is a video demo on the YouTubes: TODO 10 | 11 | ## Requirements and support 12 | 13 | Uses Stuart Knightley's JSZip: http://stuk.github.io/jszip/ 14 | and Eli Grey's FileSaver: https://github.com/eligrey/FileSaver.js/ 15 | 16 | It was tested in Chrome, Firefox, Opera and Safari on OSX. I also showed it to a cat and it approved. 17 | 18 | ## How to use 19 | 20 | Start by dropping some images on the grey box and you will see the generated thumbnails. Hovering over the thumbnails shows you their file names and size and clicking them removes them from the collection. 21 | 22 | You can download them all in Zip format by clicking the "Download as Zip" button. 23 | 24 | The thumbnails are the same name as the original pictures followed by "_tn". 25 | 26 | You can select a few options how to generate the thumbnails: 27 | 28 | * They can be on a coloured background or transparent 29 | * They can be cropped to their size instead of being the thumbnail size 30 | * You can define the thumbnail size 31 | * You can force a conversion to JPG for all of them - this results in smaller files but affects their quality. You can define the quality percentage - lower values result in more blurry images. -------------------------------------------------------------------------------- /canvasthumber.js: -------------------------------------------------------------------------------- 1 | /* 2 | canvasthumber by Christian Heilmann 3 | Version: 1.0 4 | Homepage: http://thewebrocks/demos/canvasthumber 5 | Copyright (c) 2012, Christian Heilmann 6 | Code licensed under the BSD License: 7 | http://wait-till-i.com/license.txt 8 | */ 9 | (function(){ 10 | var s = document.querySelector('#dropzone'); 11 | var o = document.querySelector('output'); 12 | var cr = document.querySelector('#crop'); 13 | var z = document.querySelector('#zip'); 14 | var t = document.querySelector('#thumbslist'); 15 | var r = document.querySelector('#remove'); 16 | var j = document.querySelector('#jpeg'); 17 | var c = document.createElement('canvas'); 18 | var q = document.querySelector('#quality'); 19 | var cx = c.getContext('2d'); 20 | var thumbwidth = 100; 21 | var thumbheight = 100; 22 | var crop = false; 23 | var background = 'white'; 24 | var jpeg = false; 25 | var quality = 0.8; 26 | zip.addEventListener('click', zipit, false); 27 | r.addEventListener('click', purgethumbs, false); 28 | 29 | function init() { 30 | if (typeof FileReader !== 'undefined') { 31 | document.body.classList.add('dragdrop'); 32 | s.innerHTML = 'Drop images here'; 33 | cr.addEventListener('click', function (ev) { 34 | document.body.classList.toggle('cropon'); 35 | }, false ); 36 | j.addEventListener('click', function (ev) { 37 | document.body.classList.toggle('jpegon'); 38 | }, false ); 39 | q.addEventListener('mousemove', function (ev) { 40 | this.nextSibling.innerHTML = this.value+'%'; 41 | }, false ); 42 | q.addEventListener('keyup', function (ev) { 43 | this.nextSibling.innerHTML = this.value+'%'; 44 | }, false ); 45 | z.addEventListener('click', zipit, false ); 46 | r.addEventListener('click', purgethumbs, false ); 47 | o.addEventListener('click', function (ev) { 48 | var t = ev.target; 49 | if (t.tagName === 'IMG') { 50 | while (t.tagName !== 'LI') { 51 | t = t.parentNode; 52 | } 53 | t.parentNode.removeChild(t); 54 | } 55 | }, false ); 56 | s.addEventListener('dragover', function ( ev ) { 57 | ev.preventDefault(); 58 | }, false ); 59 | s.addEventListener('drop', getfiles, false ); 60 | } 61 | } 62 | 63 | function getfiles(ev) { 64 | o.classList.add('doingit'); 65 | var files = ev.dataTransfer.files, 66 | url = window.URL || window.webkitURL, 67 | objURL = url.createObjectURL || false; 68 | 69 | if ( files.length > 0 ) { 70 | var i = files.length; 71 | while ( i-- ) { 72 | var file = files[ i ]; 73 | if ( file.type.indexOf('image') === -1 ) { continue; } 74 | if(objURL) { 75 | loadImage(url.createObjectURL(file),file.name); 76 | } else { 77 | var reader = new FileReader(); 78 | reader.readAsDataURL( file ); 79 | reader.onload = function ( ev ) { 80 | loadImage(ev.target.result,file.name); 81 | } 82 | } 83 | } 84 | } 85 | ev.preventDefault(); 86 | } 87 | 88 | function loadImage(file, name) { 89 | var img = new Image(); 90 | img.src = file; 91 | img.onload = function() { 92 | grabformvalues(); 93 | imagetocanvas( this, thumbwidth, thumbheight, crop, background, name ); 94 | }; 95 | } 96 | function grabformvalues() { 97 | thumbwidth = document.querySelector('#width').value; 98 | thumbheight = document.querySelector('#height').value; 99 | crop = document.querySelector('#crop').checked; 100 | background = document.querySelector('#bg').value; 101 | jpeg = document.querySelector('#jpeg').checked, 102 | quality = q.value / 100; 103 | } 104 | function imagetocanvas( img, thumbwidth, thumbheight, crop, background, name ) { 105 | c.width = thumbwidth; 106 | c.height = thumbheight; 107 | var dimensions = resize( img.width, img.height, thumbwidth, thumbheight ); 108 | if ( crop ) { 109 | c.width = dimensions.w; 110 | c.height = dimensions.h; 111 | dimensions.x = 0; 112 | dimensions.y = 0; 113 | } 114 | if ( background !== 'transparent') { 115 | cx.fillStyle = background; 116 | cx.fillRect ( 0, 0, thumbwidth, thumbheight ); 117 | } 118 | cx.drawImage( 119 | img, dimensions.x, dimensions.y, dimensions.w, dimensions.h 120 | ); 121 | addtothumbslist( jpeg, quality, name ); 122 | } 123 | 124 | function addtothumbslist(jpeg, quality, name) { 125 | var thumb = new Image(), 126 | url = jpeg ? c.toDataURL('image/jpeg', quality) : c.toDataURL(); 127 | thumb.src = url; 128 | var thumbname = name.split('.'); 129 | thumbname = thumbname[0] + '_tn.' + (jpeg ? 'jpg' : thumbname[1]); 130 | thumb.title = thumbname +' ' + Math.round(url.length / 1000 * 100) / 100 + ' KB'; 131 | thumb.setAttribute('data-filename', thumbname); 132 | var item = document.createElement('li'); 133 | var textlabel = document.createElement('span'); 134 | textlabel.innerHTML = thumb.title; 135 | item.appendChild(thumb); 136 | item.appendChild(textlabel); 137 | t.appendChild(item); 138 | } 139 | function purgethumbs() { 140 | t.innerHTML = ''; 141 | } 142 | function zipit() { 143 | var zip = new JSZip(); 144 | var imgs = o.querySelectorAll('img'); 145 | var allimgs = imgs.length; 146 | while (allimgs--) { 147 | zip.file( 148 | imgs[allimgs].getAttribute('data-filename'), 149 | imgs[allimgs].src.substr(imgs[allimgs].src.indexOf(',') + 1), 150 | { base64: true } 151 | ); 152 | } 153 | saveAs( 154 | zip.generate({type: 'blob'}), 155 | 'thumbnails.zip' 156 | ); 157 | } 158 | 159 | function resize( imagewidth, imageheight, thumbwidth, thumbheight ) { 160 | var w = 0, h = 0, x = 0, y = 0, 161 | widthratio = imagewidth / thumbwidth, 162 | heightratio = imageheight / thumbheight, 163 | maxratio = Math.max( widthratio, heightratio ); 164 | if ( maxratio > 1 ) { 165 | w = imagewidth / maxratio; 166 | h = imageheight / maxratio; 167 | } else { 168 | w = imagewidth; 169 | h = imageheight; 170 | } 171 | x = ( thumbwidth - w ) / 2; 172 | y = ( thumbheight - h ) / 2; 173 | return { w:w, h:h, x:x, y:y }; 174 | } 175 | init(); 176 | })(); 177 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |>>24,p>>>=w,q-=w,w=v>>>16&255,0===w)C[h++]=65535&v;else{if(!(16&w)){if(0===(64&w)){v=r[(65535&v)+(p&(1<q&&(p+=B[f++]< >>=w,q-=w),15>q&&(p+=B[f++]<>>24,p>>>=w,q-=w,w=v>>>16&255,!(16&w)){if(0===(64&w)){v=s[(65535&v)+(p&(1<q&&(p+=B[f++]< q&&(p+=B[f++]<k){a.msg="invalid distance too far back",e.mode=c;break a}if(p>>>=w,q-=w,w=h-i,y>w){if(w=y-w,w>m&&e.sane){a.msg="invalid distance too far back",e.mode=c;break a}if(z=0,A=o,0===n){if(z+=l-w,x>w){x-=w;do C[h++]=o[z++];while(--w);z=h-y,A=C}}else if(w>n){if(z+=l+n-w,w-=n,x>w){x-=w;do C[h++]=o[z++];while(--w);if(z=0,x>n){w=n,x-=w;do C[h++]=o[z++];while(--w);z=h-y,A=C}}}else if(z+=n-w,x>w){x-=w;do C[h++]=o[z++];while(--w);z=h-y,A=C}for(;x>2;)C[h++]=A[z++],C[h++]=A[z++],C[h++]=A[z++],x-=3;x&&(C[h++]=A[z++],x>1&&(C[h++]=A[z++]))}else{z=h-y;do C[h++]=C[z++],C[h++]=C[z++],C[h++]=C[z++],x-=3;while(x>2);x&&(C[h++]=C[z++],x>1&&(C[h++]=C[z++]))}break}}break}}while(g>f&&j>h);x=q>>3,f-=x,q-=x<<3,p&=(1<f?5+(g-f):5-(f-g),a.avail_out=j>h?257+(j-h):257-(h-j),e.hold=p,e.bits=q}},{}],35:[function(a,b,c){"use strict";function d(a){return(a>>>24&255)+(a>>>8&65280)+((65280&a)<<8)+((255&a)<<24)}function e(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new r.Buf16(320),this.work=new r.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function f(a){var b;return a&&a.state?(b=a.state,a.total_in=a.total_out=b.total=0,a.msg="",b.wrap&&(a.adler=1&b.wrap),b.mode=K,b.last=0,b.havedict=0,b.dmax=32768,b.head=null,b.hold=0,b.bits=0,b.lencode=b.lendyn=new r.Buf32(ob),b.distcode=b.distdyn=new r.Buf32(pb),b.sane=1,b.back=-1,C):F}function g(a){var b;return a&&a.state?(b=a.state,b.wsize=0,b.whave=0,b.wnext=0,f(a)):F}function h(a,b){var c,d;return a&&a.state?(d=a.state,0>b?(c=0,b=-b):(c=(b>>4)+1,48>b&&(b&=15)),b&&(8>b||b>15)?F:(null!==d.window&&d.wbits!==b&&(d.window=null),d.wrap=c,d.wbits=b,g(a))):F}function i(a,b){var c,d;return a?(d=new e,a.state=d,d.window=null,c=h(a,b),c!==C&&(a.state=null),c):F}function j(a){return i(a,rb)}function k(a){if(sb){var b;for(p=new r.Buf32(512),q=new r.Buf32(32),b=0;144>b;)a.lens[b++]=8;for(;256>b;)a.lens[b++]=9;for(;280>b;)a.lens[b++]=7;for(;288>b;)a.lens[b++]=8;for(v(x,a.lens,0,288,p,0,a.work,{bits:9}),b=0;32>b;)a.lens[b++]=5;v(y,a.lens,0,32,q,0,a.work,{bits:5}),sb=!1}a.lencode=p,a.lenbits=9,a.distcode=q,a.distbits=5}function l(a,b,c,d){var e,f=a.state;return null===f.window&&(f.wsize=1<=f.wsize?(r.arraySet(f.window,b,c-f.wsize,f.wsize,0),f.wnext=0,f.whave=f.wsize):(e=f.wsize-f.wnext,e>d&&(e=d),r.arraySet(f.window,b,c-d,e,f.wnext),d-=e,d?(r.arraySet(f.window,b,c-d,d,0),f.wnext=d,f.whave=f.wsize):(f.wnext+=e,f.wnext===f.wsize&&(f.wnext=0),f.whave n;){if(0===i)break a;i--,m+=e[g++]< >>8&255,c.check=t(c.check,Bb,2,0),m=0,n=0,c.mode=L;break}if(c.flags=0,c.head&&(c.head.done=!1),!(1&c.wrap)||(((255&m)<<8)+(m>>8))%31){a.msg="incorrect header check",c.mode=lb;break}if((15&m)!==J){a.msg="unknown compression method",c.mode=lb;break}if(m>>>=4,n-=4,wb=(15&m)+8,0===c.wbits)c.wbits=wb;else if(wb>c.wbits){a.msg="invalid window size",c.mode=lb;break}c.dmax=1< n;){if(0===i)break a;i--,m+=e[g++]< >8&1),512&c.flags&&(Bb[0]=255&m,Bb[1]=m>>>8&255,c.check=t(c.check,Bb,2,0)),m=0,n=0,c.mode=M;case M:for(;32>n;){if(0===i)break a;i--,m+=e[g++]< >>8&255,Bb[2]=m>>>16&255,Bb[3]=m>>>24&255,c.check=t(c.check,Bb,4,0)),m=0,n=0,c.mode=N;case N:for(;16>n;){if(0===i)break a;i--,m+=e[g++]< >8),512&c.flags&&(Bb[0]=255&m,Bb[1]=m>>>8&255,c.check=t(c.check,Bb,2,0)),m=0,n=0,c.mode=O;case O:if(1024&c.flags){for(;16>n;){if(0===i)break a;i--,m+=e[g++]< >>8&255,c.check=t(c.check,Bb,2,0)),m=0,n=0}else c.head&&(c.head.extra=null);c.mode=P;case P:if(1024&c.flags&&(q=c.length,q>i&&(q=i),q&&(c.head&&(wb=c.head.extra_len-c.length,c.head.extra||(c.head.extra=new Array(c.head.extra_len)),r.arraySet(c.head.extra,e,g,q,wb)),512&c.flags&&(c.check=t(c.check,e,q,g)),i-=q,g+=q,c.length-=q),c.length))break a;c.length=0,c.mode=Q;case Q:if(2048&c.flags){if(0===i)break a;q=0;do wb=e[g+q++],c.head&&wb&&c.length<65536&&(c.head.name+=String.fromCharCode(wb));while(wb&&i>q);if(512&c.flags&&(c.check=t(c.check,e,q,g)),i-=q,g+=q,wb)break a}else c.head&&(c.head.name=null);c.length=0,c.mode=R;case R:if(4096&c.flags){if(0===i)break a;q=0;do wb=e[g+q++],c.head&&wb&&c.length<65536&&(c.head.comment+=String.fromCharCode(wb));while(wb&&i>q);if(512&c.flags&&(c.check=t(c.check,e,q,g)),i-=q,g+=q,wb)break a}else c.head&&(c.head.comment=null);c.mode=S;case S:if(512&c.flags){for(;16>n;){if(0===i)break a;i--,m+=e[g++]< >9&1,c.head.done=!0),a.adler=c.check=0,c.mode=V;break;case T:for(;32>n;){if(0===i)break a;i--,m+=e[g++]< >>=7&n,n-=7&n,c.mode=ib;break}for(;3>n;){if(0===i)break a;i--,m+=e[g++]< >>=1,n-=1,3&m){case 0:c.mode=X;break;case 1:if(k(c),c.mode=bb,b===B){m>>>=2,n-=2;break a}break;case 2:c.mode=$;break;case 3:a.msg="invalid block type",c.mode=lb}m>>>=2,n-=2;break;case X:for(m>>>=7&n,n-=7&n;32>n;){if(0===i)break a;i--,m+=e[g++]< >>16^65535)){a.msg="invalid stored block lengths",c.mode=lb;break}if(c.length=65535&m,m=0,n=0,c.mode=Y,b===B)break a;case Y:c.mode=Z;case Z:if(q=c.length){if(q>i&&(q=i),q>j&&(q=j),0===q)break a;r.arraySet(f,e,g,q,h),i-=q,g+=q,j-=q,h+=q,c.length-=q;break}c.mode=V;break;case $:for(;14>n;){if(0===i)break a;i--,m+=e[g++]< >>=5,n-=5,c.ndist=(31&m)+1,m>>>=5,n-=5,c.ncode=(15&m)+4,m>>>=4,n-=4,c.nlen>286||c.ndist>30){a.msg="too many length or distance symbols",c.mode=lb;break}c.have=0,c.mode=_;case _:for(;c.have n;){if(0===i)break a;i--,m+=e[g++]< >>=3,n-=3}for(;c.have<19;)c.lens[Cb[c.have++]]=0;if(c.lencode=c.lendyn,c.lenbits=7,yb={bits:c.lenbits},xb=v(w,c.lens,0,19,c.lencode,0,c.work,yb),c.lenbits=yb.bits,xb){a.msg="invalid code lengths set",c.mode=lb;break}c.have=0,c.mode=ab;case ab:for(;c.have >>24,rb=Ab>>>16&255,sb=65535&Ab,!(n>=qb);){if(0===i)break a;i--,m+=e[g++]< sb)m>>>=qb,n-=qb,c.lens[c.have++]=sb;else{if(16===sb){for(zb=qb+2;zb>n;){if(0===i)break a;i--,m+=e[g++]< >>=qb,n-=qb,0===c.have){a.msg="invalid bit length repeat",c.mode=lb;break}wb=c.lens[c.have-1],q=3+(3&m),m>>>=2,n-=2}else if(17===sb){for(zb=qb+3;zb>n;){if(0===i)break a;i--,m+=e[g++]< >>=qb,n-=qb,wb=0,q=3+(7&m),m>>>=3,n-=3}else{for(zb=qb+7;zb>n;){if(0===i)break a;i--,m+=e[g++]< >>=qb,n-=qb,wb=0,q=11+(127&m),m>>>=7,n-=7}if(c.have+q>c.nlen+c.ndist){a.msg="invalid bit length repeat",c.mode=lb;break}for(;q--;)c.lens[c.have++]=wb}}if(c.mode===lb)break;if(0===c.lens[256]){a.msg="invalid code -- missing end-of-block",c.mode=lb;break}if(c.lenbits=9,yb={bits:c.lenbits},xb=v(x,c.lens,0,c.nlen,c.lencode,0,c.work,yb),c.lenbits=yb.bits,xb){a.msg="invalid literal/lengths set",c.mode=lb;break}if(c.distbits=6,c.distcode=c.distdyn,yb={bits:c.distbits},xb=v(y,c.lens,c.nlen,c.ndist,c.distcode,0,c.work,yb),c.distbits=yb.bits,xb){a.msg="invalid distances set",c.mode=lb;break}if(c.mode=bb,b===B)break a;case bb:c.mode=cb;case cb:if(i>=6&&j>=258){a.next_out=h,a.avail_out=j,a.next_in=g,a.avail_in=i,c.hold=m,c.bits=n,u(a,p),h=a.next_out,f=a.output,j=a.avail_out,g=a.next_in,e=a.input,i=a.avail_in,m=c.hold,n=c.bits,c.mode===V&&(c.back=-1);break}for(c.back=0;Ab=c.lencode[m&(1< >>24,rb=Ab>>>16&255,sb=65535&Ab,!(n>=qb);){if(0===i)break a;i--,m+=e[g++]< >tb)],qb=Ab>>>24,rb=Ab>>>16&255,sb=65535&Ab,!(n>=tb+qb);){if(0===i)break a;i--,m+=e[g++]< >>=tb,n-=tb,c.back+=tb}if(m>>>=qb,n-=qb,c.back+=qb,c.length=sb,0===rb){c.mode=hb;break}if(32&rb){c.back=-1,c.mode=V;break}if(64&rb){a.msg="invalid literal/length code",c.mode=lb;break}c.extra=15&rb,c.mode=db;case db:if(c.extra){for(zb=c.extra;zb>n;){if(0===i)break a;i--,m+=e[g++]< >>=c.extra,n-=c.extra,c.back+=c.extra}c.was=c.length,c.mode=eb;case eb:for(;Ab=c.distcode[m&(1< >>24,rb=Ab>>>16&255,sb=65535&Ab,!(n>=qb);){if(0===i)break a;i--,m+=e[g++]< >tb)],qb=Ab>>>24,rb=Ab>>>16&255,sb=65535&Ab,!(n>=tb+qb);){if(0===i)break a;i--,m+=e[g++]< >>=tb,n-=tb,c.back+=tb}if(m>>>=qb,n-=qb,c.back+=qb,64&rb){a.msg="invalid distance code",c.mode=lb;break}c.offset=sb,c.extra=15&rb,c.mode=fb;case fb:if(c.extra){for(zb=c.extra;zb>n;){if(0===i)break a;i--,m+=e[g++]< >>=c.extra,n-=c.extra,c.back+=c.extra}if(c.offset>c.dmax){a.msg="invalid distance too far back",c.mode=lb;break}c.mode=gb;case gb:if(0===j)break a; 14 | if(q=p-j,c.offset>q){if(q=c.offset-q,q>c.whave&&c.sane){a.msg="invalid distance too far back",c.mode=lb;break}q>c.wnext?(q-=c.wnext,ob=c.wsize-q):ob=c.wnext-q,q>c.length&&(q=c.length),pb=c.window}else pb=f,ob=h-c.offset,q=c.length;q>j&&(q=j),j-=q,c.length-=q;do f[h++]=pb[ob++];while(--q);0===c.length&&(c.mode=cb);break;case hb:if(0===j)break a;f[h++]=c.length,j--,c.mode=cb;break;case ib:if(c.wrap){for(;32>n;){if(0===i)break a;i--,m|=e[g++]< n;){if(0===i)break a;i--,m+=e[g++]< =D;D++)P[D]=0;for(E=0;o>E;E++)P[b[n+E]]++;for(H=C,G=d;G>=1&&0===P[G];G--);if(H>G&&(H=G),0===G)return p[q++]=20971520,p[q++]=20971520,s.bits=1,0;for(F=1;G>F&&0===P[F];F++);for(F>H&&(H=F),K=1,D=1;d>=D;D++)if(K<<=1,K-=P[D],0>K)return-1;if(K>0&&(a===g||1!==G))return-1;for(Q[1]=0,D=1;d>D;D++)Q[D+1]=Q[D]+P[D];for(E=0;o>E;E++)0!==b[n+E]&&(r[Q[b[n+E]]++]=E);if(a===g?(N=R=r,y=19):a===h?(N=j,O-=257,R=k,S-=257,y=256):(N=l,R=m,y=-1),M=0,E=0,D=F,x=q,I=H,J=0,v=-1,L=1< e||a===i&&L>f)return 1;for(var T=0;;){T++,z=D-J,r[E] y?(A=R[S+r[E]],B=N[O+r[E]]):(A=96,B=0),t=1< >J)+u]=z<<24|A<<16|B|0;while(0!==u);for(t=1< >=1;if(0!==t?(M&=t-1,M+=t):M=0,E++,0===--P[D]){if(D===G)break;D=b[n+r[E]]}if(D>H&&(M&w)!==v){for(0===J&&(J=H),x+=F,I=D-J,K=1<I+J&&(K-=P[I+J],!(0>=K));)I++,K<<=1;if(L+=1<e||a===i&&L>f)return 1;v=M&w,p[v]=H<<24|I<<16|x-q|0}}return 0!==M&&(p[x+M]=D-J<<24|64<<16|0),s.bits=H,0}},{"../utils/common":27}],37:[function(a,b){"use strict";b.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],38:[function(a,b,c){"use strict";function d(a){for(var b=a.length;--b>=0;)a[b]=0}function e(a){return 256>a?gb[a]:gb[256+(a>>>7)]}function f(a,b){a.pending_buf[a.pending++]=255&b,a.pending_buf[a.pending++]=b>>>8&255}function g(a,b,c){a.bi_valid>V-c?(a.bi_buf|=b< >V-a.bi_valid,a.bi_valid+=c-V):(a.bi_buf|=b< >>=1,c<<=1;while(--b>0);return c>>>1}function j(a){16===a.bi_valid?(f(a,a.bi_buf),a.bi_buf=0,a.bi_valid=0):a.bi_valid>=8&&(a.pending_buf[a.pending++]=255&a.bi_buf,a.bi_buf>>=8,a.bi_valid-=8)}function k(a,b){var c,d,e,f,g,h,i=b.dyn_tree,j=b.max_code,k=b.stat_desc.static_tree,l=b.stat_desc.has_stree,m=b.stat_desc.extra_bits,n=b.stat_desc.extra_base,o=b.stat_desc.max_length,p=0;for(f=0;U>=f;f++)a.bl_count[f]=0;for(i[2*a.heap[a.heap_max]+1]=0,c=a.heap_max+1;T>c;c++)d=a.heap[c],f=i[2*i[2*d+1]+1]+1,f>o&&(f=o,p++),i[2*d+1]=f,d>j||(a.bl_count[f]++,g=0,d>=n&&(g=m[d-n]),h=i[2*d],a.opt_len+=h*(f+g),l&&(a.static_len+=h*(k[2*d+1]+g)));if(0!==p){do{for(f=o-1;0===a.bl_count[f];)f--;a.bl_count[f]--,a.bl_count[f+1]+=2,a.bl_count[o]--,p-=2}while(p>0);for(f=o;0!==f;f--)for(d=a.bl_count[f];0!==d;)e=a.heap[--c],e>j||(i[2*e+1]!==f&&(a.opt_len+=(f-i[2*e+1])*i[2*e],i[2*e+1]=f),d--)}}function l(a,b,c){var d,e,f=new Array(U+1),g=0;for(d=1;U>=d;d++)f[d]=g=g+c[d-1]<<1;for(e=0;b>=e;e++){var h=a[2*e+1];0!==h&&(a[2*e]=i(f[h]++,h))}}function m(){var a,b,c,d,e,f=new Array(U+1);for(c=0,d=0;O-1>d;d++)for(ib[d]=c,a=0;a<1<<_[d];a++)hb[c++]=d;for(hb[c-1]=d,e=0,d=0;16>d;d++)for(jb[d]=e,a=0;a<1< >=7;R>d;d++)for(jb[d]=e<<7,a=0;a<1< =b;b++)f[b]=0;for(a=0;143>=a;)eb[2*a+1]=8,a++,f[8]++;for(;255>=a;)eb[2*a+1]=9,a++,f[9]++;for(;279>=a;)eb[2*a+1]=7,a++,f[7]++;for(;287>=a;)eb[2*a+1]=8,a++,f[8]++;for(l(eb,Q+1,f),a=0;R>a;a++)fb[2*a+1]=5,fb[2*a]=i(a,5);kb=new nb(eb,_,P+1,Q,U),lb=new nb(fb,ab,0,R,U),mb=new nb(new Array(0),bb,0,S,W)}function n(a){var b;for(b=0;Q>b;b++)a.dyn_ltree[2*b]=0;for(b=0;R>b;b++)a.dyn_dtree[2*b]=0;for(b=0;S>b;b++)a.bl_tree[2*b]=0;a.dyn_ltree[2*X]=1,a.opt_len=a.static_len=0,a.last_lit=a.matches=0}function o(a){a.bi_valid>8?f(a,a.bi_buf):a.bi_valid>0&&(a.pending_buf[a.pending++]=a.bi_buf),a.bi_buf=0,a.bi_valid=0}function p(a,b,c,d){o(a),d&&(f(a,c),f(a,~c)),E.arraySet(a.pending_buf,a.window,b,c,a.pending),a.pending+=c}function q(a,b,c,d){var e=2*b,f=2*c;return a[e]c;c++)0!==f[2*c]?(a.heap[++a.heap_len]=j=c,a.depth[c]=0):f[2*c+1]=0;for(;a.heap_len<2;)e=a.heap[++a.heap_len]=2>j?++j:0,f[2*e]=1,a.depth[e]=0,a.opt_len--,h&&(a.static_len-=g[2*e+1]);for(b.max_code=j,c=a.heap_len>>1;c>=1;c--)r(a,f,c);e=i;do c=a.heap[1],a.heap[1]=a.heap[a.heap_len--],r(a,f,1),d=a.heap[1],a.heap[--a.heap_max]=c,a.heap[--a.heap_max]=d,f[2*e]=f[2*c]+f[2*d],a.depth[e]=(a.depth[c]>=a.depth[d]?a.depth[c]:a.depth[d])+1,f[2*c+1]=f[2*d+1]=e,a.heap[1]=e++,r(a,f,1);while(a.heap_len>=2);a.heap[--a.heap_max]=a.heap[1],k(a,b),l(f,j,a.bl_count)}function u(a,b,c){var d,e,f=-1,g=b[1],h=0,i=7,j=4;for(0===g&&(i=138,j=3),b[2*(c+1)+1]=65535,d=0;c>=d;d++)e=g,g=b[2*(d+1)+1],++hh?a.bl_tree[2*e]+=h:0!==e?(e!==f&&a.bl_tree[2*e]++,a.bl_tree[2*Y]++):10>=h?a.bl_tree[2*Z]++:a.bl_tree[2*$]++,h=0,f=e,0===g?(i=138,j=3):e===g?(i=6,j=3):(i=7,j=4))}function v(a,b,c){var d,e,f=-1,i=b[1],j=0,k=7,l=4;for(0===i&&(k=138,l=3),d=0;c>=d;d++)if(e=i,i=b[2*(d+1)+1],!(++j j){do h(a,e,a.bl_tree);while(0!==--j)}else 0!==e?(e!==f&&(h(a,e,a.bl_tree),j--),h(a,Y,a.bl_tree),g(a,j-3,2)):10>=j?(h(a,Z,a.bl_tree),g(a,j-3,3)):(h(a,$,a.bl_tree),g(a,j-11,7));j=0,f=e,0===i?(k=138,l=3):e===i?(k=6,l=3):(k=7,l=4)}}function w(a){var b;for(u(a,a.dyn_ltree,a.l_desc.max_code),u(a,a.dyn_dtree,a.d_desc.max_code),t(a,a.bl_desc),b=S-1;b>=3&&0===a.bl_tree[2*cb[b]+1];b--);return a.opt_len+=3*(b+1)+5+5+4,b}function x(a,b,c,d){var e;for(g(a,b-257,5),g(a,c-1,5),g(a,d-4,4),e=0;d>e;e++)g(a,a.bl_tree[2*cb[e]+1],3);v(a,a.dyn_ltree,b-1),v(a,a.dyn_dtree,c-1)}function y(a){var b,c=4093624447;for(b=0;31>=b;b++,c>>>=1)if(1&c&&0!==a.dyn_ltree[2*b])return G;if(0!==a.dyn_ltree[18]||0!==a.dyn_ltree[20]||0!==a.dyn_ltree[26])return H;for(b=32;P>b;b++)if(0!==a.dyn_ltree[2*b])return H;return G}function z(a){pb||(m(),pb=!0),a.l_desc=new ob(a.dyn_ltree,kb),a.d_desc=new ob(a.dyn_dtree,lb),a.bl_desc=new ob(a.bl_tree,mb),a.bi_buf=0,a.bi_valid=0,n(a)}function A(a,b,c,d){g(a,(J<<1)+(d?1:0),3),p(a,b,c,!0)}function B(a){g(a,K<<1,3),h(a,X,eb),j(a)}function C(a,b,c,d){var e,f,h=0;a.level>0?(a.strm.data_type===I&&(a.strm.data_type=y(a)),t(a,a.l_desc),t(a,a.d_desc),h=w(a),e=a.opt_len+3+7>>>3,f=a.static_len+3+7>>>3,e>=f&&(e=f)):e=f=c+5,e>=c+4&&-1!==b?A(a,b,c,d):a.strategy===F||f===e?(g(a,(K<<1)+(d?1:0),3),s(a,eb,fb)):(g(a,(L<<1)+(d?1:0),3),x(a,a.l_desc.max_code+1,a.d_desc.max_code+1,h+1),s(a,a.dyn_ltree,a.dyn_dtree)),n(a),d&&o(a)}function D(a,b,c){return a.pending_buf[a.d_buf+2*a.last_lit]=b>>>8&255,a.pending_buf[a.d_buf+2*a.last_lit+1]=255&b,a.pending_buf[a.l_buf+a.last_lit]=255&c,a.last_lit++,0===b?a.dyn_ltree[2*c]++:(a.matches++,b--,a.dyn_ltree[2*(hb[c]+P+1)]++,a.dyn_dtree[2*e(b)]++),a.last_lit===a.lit_bufsize-1}var E=a("../utils/common"),F=4,G=0,H=1,I=2,J=0,K=1,L=2,M=3,N=258,O=29,P=256,Q=P+1+O,R=30,S=19,T=2*Q+1,U=15,V=16,W=7,X=256,Y=16,Z=17,$=18,_=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],ab=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],bb=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],cb=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],db=512,eb=new Array(2*(Q+2));d(eb);var fb=new Array(2*R);d(fb);var gb=new Array(db);d(gb);var hb=new Array(N-M+1);d(hb);var ib=new Array(O);d(ib);var jb=new Array(R);d(jb);var kb,lb,mb,nb=function(a,b,c,d,e){this.static_tree=a,this.extra_bits=b,this.extra_base=c,this.elems=d,this.max_length=e,this.has_stree=a&&a.length},ob=function(a,b){this.dyn_tree=a,this.max_code=0,this.stat_desc=b},pb=!1;c._tr_init=z,c._tr_stored_block=A,c._tr_flush_block=C,c._tr_tally=D,c._tr_align=B},{"../utils/common":27}],39:[function(a,b){"use strict";function c(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}b.exports=c},{}]},{},[9])(9)}); -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | body { 6 | font-size: 15px; 7 | font-family: helvetica, arial, sans-serif; 8 | color: #ccc; 9 | background: #000; 10 | 11 | } 12 | footer, section, output, header, aside, figure { 13 | display: block; 14 | } 15 | a { 16 | color: #ccc; 17 | } 18 | h1 { 19 | font-size: 24px; 20 | padding-bottom: 10px; 21 | } 22 | .dragdrop #dropzone { 23 | background: #ccc; 24 | color: #000; 25 | box-shadow:3px 3px 3px 2px rgba(0,0,0,0.9) inset; 26 | text-align: center; 27 | line-height: 200px; 28 | } 29 | .dragdrop output { 30 | display: block; 31 | } 32 | output img { 33 | margin: 5px; 34 | display: block; 35 | float: left; 36 | } 37 | footer { 38 | clear:both; 39 | } 40 | input[type=number] { width: 5em; padding: 5px;} 41 | input[type=checkbox] { margin-left: 5px } 42 | label { 43 | padding: 10px 5px; 44 | } 45 | .sidebar { 46 | background: #036; 47 | width: 300px; 48 | float: left; 49 | min-height: 650px; 50 | } 51 | #bg { 52 | width: 5em; 53 | } 54 | .jpeg { 55 | opacity: 0.2; 56 | -webkit-transition: 1s; 57 | -moz-transition: 1s; 58 | -ms-transition: 1s; 59 | -o-transition: 1s; 60 | transition: 1s; 61 | } 62 | .jpeg span { 63 | padding: 0 0px; 64 | } 65 | .crop { 66 | display: block; 67 | opacity: 1; 68 | padding-top: 10px; 69 | -webkit-transition: 1s; 70 | -moz-transition: 1s; 71 | -ms-transition: 1s; 72 | -o-transition: 1s; 73 | transition: 1s; 74 | } 75 | .cropon .crop { 76 | opacity: 0.2; 77 | } 78 | .jpegon .jpeg { 79 | opacity: 1; 80 | } 81 | fieldset { 82 | margin-bottom: 10px; 83 | border: none; 84 | } 85 | legend { 86 | display: block; 87 | padding: 10px 5px; 88 | font-size: 16px; 89 | width: calc(100% - 10px); 90 | } 91 | h1 { 92 | text-transform: uppercase; 93 | color: #fff; 94 | font-size: 22px; 95 | font-weight: normal; 96 | background: #000; 97 | 98 | padding: 10px 10px 5px 10px; 99 | letter-spacing: -1px; 100 | } 101 | header p { 102 | padding: 5px 10px 20px 10px; 103 | 104 | } 105 | #thumbslist { 106 | position: relative; 107 | padding-top: 2em; 108 | } 109 | 110 | #thumbslist li { 111 | float: left; 112 | list-style: none; 113 | } 114 | #thumbslist span { 115 | display: none; 116 | position: absolute; 117 | left: 10px; 118 | color: #fff; 119 | top: 5px; 120 | } 121 | #thumbslist li:hover span { 122 | display: block; 123 | } 124 | output img { 125 | display:block; 126 | } 127 | output button { 128 | opacity: 0; 129 | background: #090; 130 | color: #fff; 131 | margin-left: 10px; 132 | font-size: 14px; 133 | border: none; 134 | padding: 5px 10px; 135 | transition: 0.5s; 136 | } 137 | output.doingit button { 138 | opacity: 1; 139 | } 140 | h2 { 141 | text-transform: uppercase; 142 | letter-spacing: -1px; 143 | font-size: 18px; 144 | padding: 10px; 145 | background: #000; 146 | font-weight: normal; 147 | } 148 | output { 149 | display: block; 150 | float: left; 151 | background: #222; 152 | width: calc(100% - 300px); 153 | min-height: 650px; 154 | } 155 | output h2 { 156 | background: transparent; 157 | opacity: 0; 158 | transition: 0.5s; 159 | } 160 | output.doingit h2 { 161 | opacity: 1; 162 | } 163 | .doingit .teaser { 164 | display: none; 165 | } 166 | .teaser { 167 | position: absolute; 168 | top: 150px; 169 | font-size: 24px; 170 | color: #fff; 171 | line-height: 100px; 172 | animation: bounce 1s alternate infinite; 173 | -webkit-animation: bounce 1s alternate infinite; 174 | } 175 | @-webkit-keyframes bounce { 176 | from { 177 | margin-left: 50px; 178 | } 179 | to { 180 | margin-left: 10px; 181 | } 182 | } 183 | @keyframes bounce { 184 | from { 185 | margin-left: 50px; 186 | } 187 | to { 188 | margin-left: 10px; 189 | } 190 | } 191 | .teaser span { 192 | font-size: 80px; 193 | display: block; 194 | float: left; 195 | padding: 0 20px; 196 | line-height: 110px; 197 | text-align: center; 198 | transform: rotateY(180deg); 199 | } 200 | footer { 201 | clear: both; 202 | text-align: center; 203 | padding: 50px 10px 20px 10px; 204 | font-size: 12px; 205 | background: #000; 206 | } 207 | footer a { 208 | color: #ccc; 209 | } 210 | --------------------------------------------------------------------------------