diff --git a/aplicmap/geral1debianv6.map b/aplicmap/geral1debianv6.map
index 359578e..fffeca7 100755
--- a/aplicmap/geral1debianv6.map
+++ b/aplicmap/geral1debianv6.map
@@ -277,4 +277,40 @@ MAP
END
END
END
+ LAYER
+ METADATA
+ "TEMA" "NAO"
+ "ESCONDIDO" "SIM"
+ "cache" "nao"
+ END
+ NAME "copyright"
+ SIZEUNITS PIXELS
+ STATUS default
+ TOLERANCE 0
+ TOLERANCEUNITS PIXELS
+ TRANSFORM FALSE
+ TYPE POINT
+ UNITS METERS
+ CLASS
+ LABEL
+ SIZE TINY
+ TYPE BITMAP
+ BUFFER 0
+ COLOR 50 50 50
+ FORCE FALSE
+ MINDISTANCE -1
+ MINFEATURESIZE -1
+ OFFSET 0 0
+ PARTIALS TRUE
+ POSITION CC
+ END
+ END
+ FEATURE
+ POINTS
+ 10 5
+ END
+ TEXT "- i3Geo"
+ END
+ END
+
END
diff --git a/ferramentas/animagif/exec.php b/ferramentas/animagif/exec.php
index 359f357..4510b23 100755
--- a/ferramentas/animagif/exec.php
+++ b/ferramentas/animagif/exec.php
@@ -1,18 +1,44 @@
+ O arquivo gif é gerado na pasta temporária e reaproveitado como cache
+
Parâmetros:
+ &tema = código do tema (mapfile) existente em i3geo/temas
+ &colunat = coluna da tabela de atributos do tema que contém o período.
+ Essa coluna será utilizada para gerar o filtro para o desenho de cada frame que comporá o gif
+ &tempo = tempo em milisegundos entre cada frame
+ &w = largura da imagem em pixels
+ &h = altura da imagem em pixels
+ &cache = sim|nao utiliza cache do arquivo gif?
+ &mapext = extensão geográfica xmin,ymin,xmax,ymax que será usada nas imagens
+ &legenda = sim|nao
+ &transparente = sim|nao
+ ";
+ exit;
+}
+//http://localhost:8014/i3geo/ferramentas/animagif/exec.php?transparente=nao&legenda=sim&tema=dengue_casos_provaveis&colunat=semana_ano_epidemiologico&w=500&h=500&mapext=-74%20-32%20-34%204
include("../../ms_configura.php");
include("../../classesphp/funcoes_gerais.php");
include("../../classesphp/pega_variaveis.php");
include("../../classesphp/carrega_ext.php");
-$nometemp = nomeRandomico();
+if($cache == "nao"){
+ $nometemp = nomeRandomico();
+} else {
+ $nometemp = md5(implode("",$_GET));
+}
+if(empty($tempo)){
+ $tempo = 40;
+}
$arqtemp = $dir_tmp."/".$nometemp;
+if(file_exists($arqtemp.".gif")){
+ $gifBinary = file_get_contents($arqtemp.".gif");
+ //retorna o gif para o navegador
+ header('Content-type: image/gif');
+ header('Content-Disposition: filename="'.$tema.'.gif"');
+ echo $gifBinary;
+ exit;
+}
//
//carrega o phpmapscript
//
@@ -71,20 +97,21 @@ for ($i=0;$i < $numlayers;$i++){
}
//ajusta o label
$l = $mapa->getlayerbyname("copyright");
-$classe = $l->getclass(0);
-$label = $classe->getLabel(0);
-$label->updatefromstring("LABEL TYPE TRUETYPE END");
-$label->set("font","arial");
-$label->set("size",15);
-$label->updatefromstring("LABEL POSITION lr END");
-//$label->updatefromstring("LABEL OUTLINECOLOR 255 255 255 OUTLINEWIDTH 10 END");
-//$labels = new styleObj($classe);
-$label->updatefromstring('LABEL STYLE GEOMTRANSFORM "labelpoly" COLOR 255 255 255 END END');
+if($l != ""){
+ $classe = $l->getclass(0);
+ $label = $classe->getLabel(0);
+ $label->updatefromstring("LABEL TYPE TRUETYPE END");
+ $label->set("font","arial");
+ $label->set("size",15);
+ $label->updatefromstring("LABEL POSITION lr END");
+ $label->updatefromstring('LABEL STYLE GEOMTRANSFORM "labelpoly" COLOR 255 255 255 END END');
+}
//
$mapa->save($arqtemp.".map");
//adiciona ao mapa base as camadas do mapfile indicado em $tema
$nmapa = ms_newMapObj($locaplic."/temas/".$tema.".map");
$numlayers = $nmapa->numlayers;
+
for ($i=0;$i < $numlayers;$i++){
$layern = $nmapa->getlayer($i);
$layern->set("status",MS_DEFAULT);
@@ -107,6 +134,7 @@ for ($i=0;$i < $numlayers;$i++){
ms_newLayerObj($mapa, $layern);
}
$mapa->save($arqtemp.".map");
+
//aplica a extensao geografica
$layer = $mapa->getlayerbyname($tema);
@@ -125,11 +153,32 @@ if ($ret != ""){
$mapa->setsize($w,$h);
$sca = $mapa->scalebar;
$sca->set("status",MS_OFF);
+if($legenda == "sim"){
+ $leg = $mapa->legend;
+ $leg->set("status",MS_EMBED);
+ $cor = $leg->imagecolor;
+ $cor->setrgb(250,250,250);
+ $labelleg = $leg->label;
+ //$labelleg->set("type",MS_TRUETYPE);
+ //$labelleg->set("font","arial");
+ $labelleg->set("size",10);
+ //$leg->set("keyspacingy",10);
+ $layer = $mapa->getlayerbyname($tema);
+ $nclass = $layer->numclasses;
+ for($i=0;$i<$nclass;$i++){
+ $classe = $layer->getclass($i);
+ if($classe->title === ""){
+ $classe->title = $classe->name;
+ }
+ }
+}
$c = $mapa->imagecolor;
$c->setrgb(-1,-1,-1);
$o = $mapa->outputformat;
$o->set("imagemode",MS_IMAGEMODE_RGBA);
-$o->set("transparent",MS_TRUE);
+if($transparente == "sim"){
+ $o->set("transparent",MS_TRUE);
+}
$mapa->save($arqtemp.".map");
$mapa = ms_newMapObj($arqtemp.".map");
if(validaAcessoTemas($arqtemp.".map",false) == true){
@@ -152,21 +201,29 @@ sort($listaunica);
$layer = $mapa->getlayerbyname($tema);
$l = $mapa->getlayerbyname("copyright");
-$c = $l->getclass(0);
-$label = $c->getLabel(0);
-
+if($l != ""){
+ $c = $l->getclass(0);
+ $label = $c->getLabel(0);
+}
$imagens = array();
$duracao = array();
$objImagem = "";
//$listaunica = array($listaunica[1]);
foreach($listaunica as $d){
- $filtro = "(([$colunat] = $d))";
+ if(strtoupper($colunat) == $colunat){
+ $filtro = "(('[$colunat]' = '$d'))";
+ }
+ else{
+ $filtro = "$colunat = '$d'";
+ }
$layer->setfilter($filtro);
+ //$mapa->save($arqtemp.".map");echo $arqtemp;exit;
$nomec = $arqtemp.$d.".png";
$s = "LABEL TEXT '".$d."' END";
- $label->updateFromString($s);
-
+ if($l != ""){
+ $label->updateFromString($s);
+ }
if($objImagem == ""){
$objImagem = $mapa->draw();
$objImagem->saveImage($nomec);
@@ -177,16 +234,17 @@ foreach($listaunica as $d){
$objImagem->saveImage($nomec);
}
$imagens[] = $nomec;
- $duracao[] = 40;
+ $duracao[] = $tempo;
}
//junta as imagens no gif
include("../../pacotes/gifcreator/GifCreator.php");
$gc = new GifCreator();
-$gc->create($imagens, $duracao, 1);
+$gc->create($imagens, $duracao, 0);
$gifBinary = $gc->getGif();
+file_put_contents($arqtemp.".gif", $gifBinary);
//retorna o gif para o navegador
header('Content-type: image/gif');
-header('Content-Disposition: filename="butterfly.gif"');
+header('Content-Disposition: filename="'.$tema.'.gif"');
echo $gifBinary;
exit;
-?>
\ No newline at end of file
+?>
diff --git a/ferramentas/animagif/index.php b/ferramentas/animagif/index.php
new file mode 100755
index 0000000..1e37421
--- /dev/null
+++ b/ferramentas/animagif/index.php
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+```
+
+### Image tag attributes:
+
+* **rel:animated_src** - If this url is specified, it's loaded into the player instead of src.
+ This allows a preview frame to be shown until animated gif data is streamed into the canvas
+
+* **rel:auto_play** - Defaults to 1 if not specified. If set to zero, a call to the play() method is needed
+
+* **rel:rubbable** - Defaults to 0 if not specified. If set to 1, the gif will be a canvas with handlers to handle rubbing.
+
+### Constructor options
+
+* **gif** - Required. The DOM element of an img tag.
+* **loop_mode** - Optional. Setting this to false will force disable looping of the gif.
+* **auto\_play** - Optional. Same as the rel:auto_play attribute above, this arg overrides the img tag info.
+* **max\_width** - Optional. Scale images over max\_width down to max_width. Helpful with mobile.
+* **rubbable** - Optional. Make it rubbable.
+* **on_end** - Optional. Add a callback for when the gif reaches the end of a single loop (one iteration). The first argument passed will be the gif HTMLElement.
+* **loop_delay** - Optional. The amount of time to pause (in ms) after each single loop (iteration).
+* **progressbar_height** - Optional. The height of the progress bar.
+* **progressbar_background_color** - Optional. The background color of the progress bar.
+* **progressbar_foreground_color** - Optional. The foreground color of the progress bar.
+
+### Instance methods
+
+#### loading
+* **load( callback )** - Loads the gif specified by the src or rel:animated_src sttributie of the img tag into a canvas element and then calls callback if one is passed
+* **load_url( src, callback )** - Loads the gif file specified in the src argument into a canvas element and then calls callback if one is passed
+
+#### play controls
+* **play** - Start playing the gif
+* **pause** - Stop playing the gif
+* **move_to(i)** - Move to frame i of the gif
+* **move_relative(i)** - Move i frames ahead (or behind if i < 0)
+
+#### getters
+* **get_canvas** - The canvas element that the gif is playing in. Handy for assigning event handlers to.
+* **get_playing** - Whether or not the gif is currently playing
+* **get_loading** - Whether or not the gif has finished loading/parsing
+* **get\_auto_play** - Whether or not the gif is set to play automatically
+* **get_length** - The number of frames in the gif
+* **get\_current_frame** - The index of the currently displayed frame of the gif
+
+## Caveat: same-domain origin
+
+The gif has to be on the same domain (and port and protocol) as the page you're loading.
+
+The library works by parsing gif image data in js, extracting individual frames, and rendering them on a canvas element. There is no way to get the raw image data from a normal image load, so this library does an XHR request for the image and forces the MIME-type to "text/plain". Consequently, using this library is subject to all the same cross-domain restrictions as any other XHR request.
diff --git a/pacotes/libgifjs/example.html b/pacotes/libgifjs/example.html
new file mode 100755
index 0000000..cd26adb
--- /dev/null
+++ b/pacotes/libgifjs/example.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+ Image via mlkshk
+
+
+
+
+ Image tag attributes:
+
+ rel:animated_src - If this url is specified, it's loaded into the player instead of src.
+ This allows a preview frame to be shown until animated gif data is streamed into the canvas
+
+ rel:auto_play - Defaults to 1 if not specified. If set to zero, a call to the play() method is needed
+
+ Constructor options args
+
+ gif Required. The DOM element of an img tag.
+ loop_mode Optional. Setting this to false will force disable looping of the gif.
+ auto_play Optional. Same as the rel:auto_play attribute above, this arg overrides the img tag info.
+ max_width Optional. Scale images over max_width down to max_width. Helpful with mobile.
+ on_end Optional. Add a callback for when the gif reaches the end of a single loop (one iteration). The first argument passed will be the gif HTMLElement.
+ loop_delay Optional. The amount of time to pause (in ms) after each single loop (iteration).
+ draw_while_loading Optional. Determines whether the gif will be drawn to the canvas whilst it is loaded.
+ show_progress_bar Optional. Only applies when draw_while_loading is set to true.
+
+ Instance methods
+
+ // loading
+ load( callback ) Loads the gif specified by the src or rel:animated_src sttributie of the img tag into a canvas element and then calls callback if one is passed
+ load_url( src, callback ) Loads the gif file specified in the src argument into a canvas element and then calls callback if one is passed
+
+ // play controls
+ play - Start playing the gif
+ pause - Stop playing the gif
+ move_to(i) - Move to frame i of the gif
+ move_relative(i) - Move i frames ahead (or behind if i < 0)
+
+ // getters
+ get_canvas The canvas element that the gif is playing in. Handy for assigning event handlers to.
+ get_playing Whether or not the gif is currently playing
+ get_loading Whether or not the gif has finished loading/parsing
+ get_auto_play Whether or not the gif is set to play automatically
+ get_length The number of frames in the gif
+ get_current_frame The index of the currently displayed frame of the gif
+
+ For additional customization (viewport inside iframe) these params may be passed:
+ c_w, c_h - width and height of canvas
+ vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport
+
+ A bonus: few articles to understand what is going on
+ http://enthusiasms.org/post/16976438906
+ http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
+ http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546
+
+*/
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define([], factory);
+ } else if (typeof exports === 'object') {
+ module.exports = factory();
+ } else {
+ root.SuperGif = factory();
+ }
+}(this, function () {
+ // Generic functions
+ var bitsToNum = function (ba) {
+ return ba.reduce(function (s, n) {
+ return s * 2 + n;
+ }, 0);
+ };
+
+ var byteToBitArr = function (bite) {
+ var a = [];
+ for (var i = 7; i >= 0; i--) {
+ a.push( !! (bite & (1 << i)));
+ }
+ return a;
+ };
+
+ // Stream
+ /**
+ * @constructor
+ */
+ // Make compiler happy.
+ var Stream = function (data) {
+ this.data = data;
+ this.len = this.data.length;
+ this.pos = 0;
+
+ this.readByte = function () {
+ if (this.pos >= this.data.length) {
+ throw new Error('Attempted to read past end of stream.');
+ }
+ if (data instanceof Uint8Array)
+ return data[this.pos++];
+ else
+ return data.charCodeAt(this.pos++) & 0xFF;
+ };
+
+ this.readBytes = function (n) {
+ var bytes = [];
+ for (var i = 0; i < n; i++) {
+ bytes.push(this.readByte());
+ }
+ return bytes;
+ };
+
+ this.read = function (n) {
+ var s = '';
+ for (var i = 0; i < n; i++) {
+ s += String.fromCharCode(this.readByte());
+ }
+ return s;
+ };
+
+ this.readUnsigned = function () { // Little-endian.
+ var a = this.readBytes(2);
+ return (a[1] << 8) + a[0];
+ };
+ };
+
+ var lzwDecode = function (minCodeSize, data) {
+ // TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String?
+ var pos = 0; // Maybe this streaming thing should be merged with the Stream?
+ var readCode = function (size) {
+ var code = 0;
+ for (var i = 0; i < size; i++) {
+ if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) {
+ code |= 1 << i;
+ }
+ pos++;
+ }
+ return code;
+ };
+
+ var output = [];
+
+ var clearCode = 1 << minCodeSize;
+ var eoiCode = clearCode + 1;
+
+ var codeSize = minCodeSize + 1;
+
+ var dict = [];
+
+ var clear = function () {
+ dict = [];
+ codeSize = minCodeSize + 1;
+ for (var i = 0; i < clearCode; i++) {
+ dict[i] = [i];
+ }
+ dict[clearCode] = [];
+ dict[eoiCode] = null;
+
+ };
+
+ var code;
+ var last;
+
+ while (true) {
+ last = code;
+ code = readCode(codeSize);
+
+ if (code === clearCode) {
+ clear();
+ continue;
+ }
+ if (code === eoiCode) break;
+
+ if (code < dict.length) {
+ if (last !== clearCode) {
+ dict.push(dict[last].concat(dict[code][0]));
+ }
+ }
+ else {
+ if (code !== dict.length) throw new Error('Invalid LZW code.');
+ dict.push(dict[last].concat(dict[last][0]));
+ }
+ output.push.apply(output, dict[code]);
+
+ if (dict.length === (1 << codeSize) && codeSize < 12) {
+ // If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long.
+ codeSize++;
+ }
+ }
+
+ // I don't know if this is technically an error, but some GIFs do it.
+ //if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.');
+ return output;
+ };
+
+
+ // The actual parsing; returns an object with properties.
+ var parseGIF = function (st, handler) {
+ handler || (handler = {});
+
+ // LZW (GIF-specific)
+ var parseCT = function (entries) { // Each entry is 3 bytes, for RGB.
+ var ct = [];
+ for (var i = 0; i < entries; i++) {
+ ct.push(st.readBytes(3));
+ }
+ return ct;
+ };
+
+ var readSubBlocks = function () {
+ var size, data;
+ data = '';
+ do {
+ size = st.readByte();
+ data += st.read(size);
+ } while (size !== 0);
+ return data;
+ };
+
+ var parseHeader = function () {
+ var hdr = {};
+ hdr.sig = st.read(3);
+ hdr.ver = st.read(3);
+ if (hdr.sig !== 'GIF') throw new Error('Not a GIF file.'); // XXX: This should probably be handled more nicely.
+ hdr.width = st.readUnsigned();
+ hdr.height = st.readUnsigned();
+
+ var bits = byteToBitArr(st.readByte());
+ hdr.gctFlag = bits.shift();
+ hdr.colorRes = bitsToNum(bits.splice(0, 3));
+ hdr.sorted = bits.shift();
+ hdr.gctSize = bitsToNum(bits.splice(0, 3));
+
+ hdr.bgColor = st.readByte();
+ hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64
+ if (hdr.gctFlag) {
+ hdr.gct = parseCT(1 << (hdr.gctSize + 1));
+ }
+ handler.hdr && handler.hdr(hdr);
+ };
+
+ var parseExt = function (block) {
+ var parseGCExt = function (block) {
+ var blockSize = st.readByte(); // Always 4
+ var bits = byteToBitArr(st.readByte());
+ block.reserved = bits.splice(0, 3); // Reserved; should be 000.
+ block.disposalMethod = bitsToNum(bits.splice(0, 3));
+ block.userInput = bits.shift();
+ block.transparencyGiven = bits.shift();
+
+ block.delayTime = st.readUnsigned();
+
+ block.transparencyIndex = st.readByte();
+
+ block.terminator = st.readByte();
+
+ handler.gce && handler.gce(block);
+ };
+
+ var parseComExt = function (block) {
+ block.comment = readSubBlocks();
+ handler.com && handler.com(block);
+ };
+
+ var parsePTExt = function (block) {
+ // No one *ever* uses this. If you use it, deal with parsing it yourself.
+ var blockSize = st.readByte(); // Always 12
+ block.ptHeader = st.readBytes(12);
+ block.ptData = readSubBlocks();
+ handler.pte && handler.pte(block);
+ };
+
+ var parseAppExt = function (block) {
+ var parseNetscapeExt = function (block) {
+ var blockSize = st.readByte(); // Always 3
+ block.unknown = st.readByte(); // ??? Always 1? What is this?
+ block.iterations = st.readUnsigned();
+ block.terminator = st.readByte();
+ handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block);
+ };
+
+ var parseUnknownAppExt = function (block) {
+ block.appData = readSubBlocks();
+ // FIXME: This won't work if a handler wants to match on any identifier.
+ handler.app && handler.app[block.identifier] && handler.app[block.identifier](block);
+ };
+
+ var blockSize = st.readByte(); // Always 11
+ block.identifier = st.read(8);
+ block.authCode = st.read(3);
+ switch (block.identifier) {
+ case 'NETSCAPE':
+ parseNetscapeExt(block);
+ break;
+ default:
+ parseUnknownAppExt(block);
+ break;
+ }
+ };
+
+ var parseUnknownExt = function (block) {
+ block.data = readSubBlocks();
+ handler.unknown && handler.unknown(block);
+ };
+
+ block.label = st.readByte();
+ switch (block.label) {
+ case 0xF9:
+ block.extType = 'gce';
+ parseGCExt(block);
+ break;
+ case 0xFE:
+ block.extType = 'com';
+ parseComExt(block);
+ break;
+ case 0x01:
+ block.extType = 'pte';
+ parsePTExt(block);
+ break;
+ case 0xFF:
+ block.extType = 'app';
+ parseAppExt(block);
+ break;
+ default:
+ block.extType = 'unknown';
+ parseUnknownExt(block);
+ break;
+ }
+ };
+
+ var parseImg = function (img) {
+ var deinterlace = function (pixels, width) {
+ // Of course this defeats the purpose of interlacing. And it's *probably*
+ // the least efficient way it's ever been implemented. But nevertheless...
+ var newPixels = new Array(pixels.length);
+ var rows = pixels.length / width;
+ var cpRow = function (toRow, fromRow) {
+ var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width);
+ newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels));
+ };
+
+ // See appendix E.
+ var offsets = [0, 4, 2, 1];
+ var steps = [8, 8, 4, 2];
+
+ var fromRow = 0;
+ for (var pass = 0; pass < 4; pass++) {
+ for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) {
+ cpRow(toRow, fromRow)
+ fromRow++;
+ }
+ }
+
+ return newPixels;
+ };
+
+ img.leftPos = st.readUnsigned();
+ img.topPos = st.readUnsigned();
+ img.width = st.readUnsigned();
+ img.height = st.readUnsigned();
+
+ var bits = byteToBitArr(st.readByte());
+ img.lctFlag = bits.shift();
+ img.interlaced = bits.shift();
+ img.sorted = bits.shift();
+ img.reserved = bits.splice(0, 2);
+ img.lctSize = bitsToNum(bits.splice(0, 3));
+
+ if (img.lctFlag) {
+ img.lct = parseCT(1 << (img.lctSize + 1));
+ }
+
+ img.lzwMinCodeSize = st.readByte();
+
+ var lzwData = readSubBlocks();
+
+ img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData);
+
+ if (img.interlaced) { // Move
+ img.pixels = deinterlace(img.pixels, img.width);
+ }
+
+ handler.img && handler.img(img);
+ };
+
+ var parseBlock = function () {
+ var block = {};
+ block.sentinel = st.readByte();
+
+ switch (String.fromCharCode(block.sentinel)) { // For ease of matching
+ case '!':
+ block.type = 'ext';
+ parseExt(block);
+ break;
+ case ',':
+ block.type = 'img';
+ parseImg(block);
+ break;
+ case ';':
+ block.type = 'eof';
+ handler.eof && handler.eof(block);
+ break;
+ default:
+ throw new Error('Unknown block: 0x' + block.sentinel.toString(16)); // TODO: Pad this with a 0.
+ }
+
+ if (block.type !== 'eof') setTimeout(parseBlock, 0);
+ };
+
+ var parse = function () {
+ parseHeader();
+ setTimeout(parseBlock, 0);
+ };
+
+ parse();
+ };
+
+ var SuperGif = function ( opts ) {
+ var options = {
+ //viewport position
+ vp_l: 0,
+ vp_t: 0,
+ vp_w: null,
+ vp_h: null,
+ //canvas sizes
+ c_w: null,
+ c_h: null
+ };
+ for (var i in opts ) { options[i] = opts[i] }
+ if (options.vp_w && options.vp_h) options.is_vp = true;
+
+ var stream;
+ var hdr;
+
+ var loadError = null;
+ var loading = false;
+
+ var transparency = null;
+ var delay = null;
+ var disposalMethod = null;
+ var disposalRestoreFromIdx = null;
+ var lastDisposalMethod = null;
+ var frame = null;
+ var lastImg = null;
+
+ var playing = true;
+ var forward = true;
+
+ var ctx_scaled = false;
+
+ var frames = [];
+ var frameOffsets = []; // elements have .x and .y properties
+
+ var gif = options.gif;
+ if (typeof options.auto_play == 'undefined')
+ options.auto_play = (!gif.getAttribute('rel:auto_play') || gif.getAttribute('rel:auto_play') == '1');
+
+ var onEndListener = (options.hasOwnProperty('on_end') ? options.on_end : null);
+ var loopDelay = (options.hasOwnProperty('loop_delay') ? options.loop_delay : 0);
+ var overrideLoopMode = (options.hasOwnProperty('loop_mode') ? options.loop_mode : 'auto');
+ var drawWhileLoading = (options.hasOwnProperty('draw_while_loading') ? options.draw_while_loading : true);
+ var showProgressBar = drawWhileLoading ? (options.hasOwnProperty('show_progress_bar') ? options.show_progress_bar : true) : false;
+ var progressBarHeight = (options.hasOwnProperty('progressbar_height') ? options.progressbar_height : 25);
+ var progressBarBackgroundColor = (options.hasOwnProperty('progressbar_background_color') ? options.progressbar_background_color : 'rgba(255,255,255,0.4)');
+ var progressBarForegroundColor = (options.hasOwnProperty('progressbar_foreground_color') ? options.progressbar_foreground_color : 'rgba(255,0,22,.8)');
+
+ var clear = function () {
+ transparency = null;
+ delay = null;
+ lastDisposalMethod = disposalMethod;
+ disposalMethod = null;
+ frame = null;
+ };
+
+ // XXX: There's probably a better way to handle catching exceptions when
+ // callbacks are involved.
+ var doParse = function () {
+ try {
+ parseGIF(stream, handler);
+ }
+ catch (err) {
+ doLoadError('parse');
+ }
+ };
+
+ var doText = function (text) {
+ toolbar.innerHTML = text; // innerText? Escaping? Whatever.
+ toolbar.style.visibility = 'visible';
+ };
+
+ var setSizes = function(w, h) {
+ canvas.width = w * get_canvas_scale();
+ canvas.height = h * get_canvas_scale();
+ toolbar.style.minWidth = ( w * get_canvas_scale() ) + 'px';
+
+ tmpCanvas.width = w;
+ tmpCanvas.height = h;
+ tmpCanvas.style.width = w + 'px';
+ tmpCanvas.style.height = h + 'px';
+ tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0);
+ };
+
+ var setFrameOffset = function(frame, offset) {
+ if (!frameOffsets[frame]) {
+ frameOffsets[frame] = offset;
+ return;
+ }
+ if (typeof offset.x !== 'undefined') {
+ frameOffsets[frame].x = offset.x;
+ }
+ if (typeof offset.y !== 'undefined') {
+ frameOffsets[frame].y = offset.y;
+ }
+ };
+
+ var doShowProgress = function (pos, length, draw) {
+ if (draw && showProgressBar) {
+ var height = progressBarHeight;
+ var left, mid, top, width;
+ if (options.is_vp) {
+ if (!ctx_scaled) {
+ top = (options.vp_t + options.vp_h - height);
+ height = height;
+ left = options.vp_l;
+ mid = left + (pos / length) * options.vp_w;
+ width = canvas.width;
+ } else {
+ top = (options.vp_t + options.vp_h - height) / get_canvas_scale();
+ height = height / get_canvas_scale();
+ left = (options.vp_l / get_canvas_scale() );
+ mid = left + (pos / length) * (options.vp_w / get_canvas_scale());
+ width = canvas.width / get_canvas_scale();
+ }
+ //some debugging, draw rect around viewport
+ if (false) {
+ if (!ctx_scaled) {
+ var l = options.vp_l, t = options.vp_t;
+ var w = options.vp_w, h = options.vp_h;
+ } else {
+ var l = options.vp_l/get_canvas_scale(), t = options.vp_t/get_canvas_scale();
+ var w = options.vp_w/get_canvas_scale(), h = options.vp_h/get_canvas_scale();
+ }
+ ctx.rect(l,t,w,h);
+ ctx.stroke();
+ }
+ }
+ else {
+ top = (canvas.height - height) / (ctx_scaled ? get_canvas_scale() : 1);
+ mid = ((pos / length) * canvas.width) / (ctx_scaled ? get_canvas_scale() : 1);
+ width = canvas.width / (ctx_scaled ? get_canvas_scale() : 1 );
+ height /= ctx_scaled ? get_canvas_scale() : 1;
+ }
+
+ ctx.fillStyle = progressBarBackgroundColor;
+ ctx.fillRect(mid, top, width - mid, height);
+
+ ctx.fillStyle = progressBarForegroundColor;
+ ctx.fillRect(0, top, mid, height);
+ }
+ };
+
+ var doLoadError = function (originOfError) {
+ var drawError = function () {
+ ctx.fillStyle = 'black';
+ ctx.fillRect(0, 0, options.c_w ? options.c_w : hdr.width, options.c_h ? options.c_h : hdr.height);
+ ctx.strokeStyle = 'red';
+ ctx.lineWidth = 3;
+ ctx.moveTo(0, 0);
+ ctx.lineTo(options.c_w ? options.c_w : hdr.width, options.c_h ? options.c_h : hdr.height);
+ ctx.moveTo(0, options.c_h ? options.c_h : hdr.height);
+ ctx.lineTo(options.c_w ? options.c_w : hdr.width, 0);
+ ctx.stroke();
+ };
+
+ loadError = originOfError;
+ hdr = {
+ width: gif.width,
+ height: gif.height
+ }; // Fake header.
+ frames = [];
+ drawError();
+ };
+
+ var doHdr = function (_hdr) {
+ hdr = _hdr;
+ setSizes(hdr.width, hdr.height)
+ };
+
+ var doGCE = function (gce) {
+ pushFrame();
+ clear();
+ transparency = gce.transparencyGiven ? gce.transparencyIndex : null;
+ delay = gce.delayTime;
+ disposalMethod = gce.disposalMethod;
+ // We don't have much to do with the rest of GCE.
+ };
+
+ var pushFrame = function () {
+ if (!frame) return;
+ frames.push({
+ data: frame.getImageData(0, 0, hdr.width, hdr.height),
+ delay: delay
+ });
+ frameOffsets.push({ x: 0, y: 0 });
+ };
+
+ var doImg = function (img) {
+ if (!frame) frame = tmpCanvas.getContext('2d');
+
+ var currIdx = frames.length;
+
+ //ct = color table, gct = global color table
+ var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists?
+
+ /*
+ Disposal method indicates the way in which the graphic is to
+ be treated after being displayed.
+
+ Values : 0 - No disposal specified. The decoder is
+ not required to take any action.
+ 1 - Do not dispose. The graphic is to be left
+ in place.
+ 2 - Restore to background color. The area used by the
+ graphic must be restored to the background color.
+ 3 - Restore to previous. The decoder is required to
+ restore the area overwritten by the graphic with
+ what was there prior to rendering the graphic.
+
+ Importantly, "previous" means the frame state
+ after the last disposal of method 0, 1, or 2.
+ */
+ if (currIdx > 0) {
+ if (lastDisposalMethod === 3) {
+ // Restore to previous
+ // If we disposed every frame including first frame up to this point, then we have
+ // no composited frame to restore to. In this case, restore to background instead.
+ if (disposalRestoreFromIdx !== null) {
+ frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0);
+ } else {
+ frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height);
+ }
+ } else {
+ disposalRestoreFromIdx = currIdx - 1;
+ }
+
+ if (lastDisposalMethod === 2) {
+ // Restore to background color
+ // Browser implementations historically restore to transparent; we do the same.
+ // http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079
+ frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height);
+ }
+ }
+ // else, Undefined/Do not dispose.
+ // frame contains final pixel data from the last frame; do nothing
+
+ //Get existing pixels for img region after applying disposal method
+ var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height);
+
+ //apply color table colors
+ img.pixels.forEach(function (pixel, i) {
+ // imgData.data === [R,G,B,A,R,G,B,A,...]
+ if (pixel !== transparency) {
+ imgData.data[i * 4 + 0] = ct[pixel][0];
+ imgData.data[i * 4 + 1] = ct[pixel][1];
+ imgData.data[i * 4 + 2] = ct[pixel][2];
+ imgData.data[i * 4 + 3] = 255; // Opaque.
+ }
+ });
+
+ frame.putImageData(imgData, img.leftPos, img.topPos);
+
+ if (!ctx_scaled) {
+ ctx.scale(get_canvas_scale(),get_canvas_scale());
+ ctx_scaled = true;
+ }
+
+ // We could use the on-page canvas directly, except that we draw a progress
+ // bar for each image chunk (not just the final image).
+ if (drawWhileLoading) {
+ ctx.drawImage(tmpCanvas, 0, 0);
+ drawWhileLoading = options.auto_play;
+ }
+
+ lastImg = img;
+ };
+
+ var player = (function () {
+ var i = -1;
+ var iterationCount = 0;
+
+ var showingInfo = false;
+ var pinned = false;
+
+ /**
+ * Gets the index of the frame "up next".
+ * @returns {number}
+ */
+ var getNextFrameNo = function () {
+ var delta = (forward ? 1 : -1);
+ return (i + delta + frames.length) % frames.length;
+ };
+
+ var stepFrame = function (amount) { // XXX: Name is confusing.
+ i = i + amount;
+
+ putFrame();
+ };
+
+ var step = (function () {
+ var stepping = false;
+
+ var completeLoop = function () {
+ if (onEndListener !== null)
+ onEndListener(gif);
+ iterationCount++;
+
+ if (overrideLoopMode !== false || iterationCount < 0) {
+ doStep();
+ } else {
+ stepping = false;
+ playing = false;
+ }
+ };
+
+ var doStep = function () {
+ stepping = playing;
+ if (!stepping) return;
+
+ stepFrame(1);
+ var delay = frames[i].delay * 10;
+ if (!delay) delay = 100; // FIXME: Should this even default at all? What should it be?
+
+ var nextFrameNo = getNextFrameNo();
+ if (nextFrameNo === 0) {
+ delay += loopDelay;
+ setTimeout(completeLoop, delay);
+ } else {
+ setTimeout(doStep, delay);
+ }
+ };
+
+ return function () {
+ if (!stepping) setTimeout(doStep, 0);
+ };
+ }());
+
+ var putFrame = function () {
+ var offset;
+ i = parseInt(i, 10);
+
+ if (i > frames.length - 1){
+ i = 0;
+ }
+
+ if (i < 0){
+ i = 0;
+ }
+
+ offset = frameOffsets[i];
+
+ tmpCanvas.getContext("2d").putImageData(frames[i].data, offset.x, offset.y);
+ ctx.globalCompositeOperation = "copy";
+ ctx.drawImage(tmpCanvas, 0, 0);
+ };
+
+ var play = function () {
+ playing = true;
+ step();
+ };
+
+ var pause = function () {
+ playing = false;
+ };
+
+
+ return {
+ init: function () {
+ if (loadError) return;
+
+ if ( ! (options.c_w && options.c_h) ) {
+ ctx.scale(get_canvas_scale(),get_canvas_scale());
+ }
+
+ if (options.auto_play) {
+ step();
+ }
+ else {
+ i = 0;
+ putFrame();
+ }
+ },
+ step: step,
+ play: play,
+ pause: pause,
+ playing: playing,
+ move_relative: stepFrame,
+ current_frame: function() { return i; },
+ length: function() { return frames.length },
+ move_to: function ( frame_idx ) {
+ i = frame_idx;
+ putFrame();
+ }
+ }
+ }());
+
+ var doDecodeProgress = function (draw) {
+ doShowProgress(stream.pos, stream.data.length, draw);
+ };
+
+ var doNothing = function () {};
+ /**
+ * @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency.
+ * Note that this means that the text will be unsynchronized with the progress bar on non-frames;
+ * but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly.
+ */
+ var withProgress = function (fn, draw) {
+ return function (block) {
+ fn(block);
+ doDecodeProgress(draw);
+ };
+ };
+
+
+ var handler = {
+ hdr: withProgress(doHdr),
+ gce: withProgress(doGCE),
+ com: withProgress(doNothing),
+ // I guess that's all for now.
+ app: {
+ // TODO: Is there much point in actually supporting iterations?
+ NETSCAPE: withProgress(doNothing)
+ },
+ img: withProgress(doImg, true),
+ eof: function (block) {
+ //toolbar.style.display = '';
+ pushFrame();
+ doDecodeProgress(false);
+ if ( ! (options.c_w && options.c_h) ) {
+ canvas.width = hdr.width * get_canvas_scale();
+ canvas.height = hdr.height * get_canvas_scale();
+ }
+ player.init();
+ loading = false;
+ if (load_callback) {
+ load_callback(gif);
+ }
+
+ }
+ };
+
+ var init = function () {
+ var parent = gif.parentNode;
+
+ var div = document.createElement('div');
+ canvas = document.createElement('canvas');
+ ctx = canvas.getContext('2d');
+ toolbar = document.createElement('div');
+
+ tmpCanvas = document.createElement('canvas');
+
+ div.width = canvas.width = gif.width;
+ div.height = canvas.height = gif.height;
+ toolbar.style.minWidth = gif.width + 'px';
+
+ div.className = 'jsgif';
+ toolbar.className = 'jsgif_toolbar';
+ div.appendChild(canvas);
+ div.appendChild(toolbar);
+
+ parent.insertBefore(div, gif);
+ parent.removeChild(gif);
+
+ if (options.c_w && options.c_h) setSizes(options.c_w, options.c_h);
+ initialized=true;
+ };
+
+ var get_canvas_scale = function() {
+ var scale;
+ if (options.max_width && hdr && hdr.width > options.max_width) {
+ scale = options.max_width / hdr.width;
+ }
+ else {
+ scale = 1;
+ }
+ return scale;
+ }
+
+ var canvas, ctx, toolbar, tmpCanvas;
+ var initialized = false;
+ var load_callback = false;
+
+ var load_setup = function(callback) {
+ if (loading) return false;
+ if (callback) load_callback = callback;
+ else load_callback = false;
+
+ loading = true;
+ frames = [];
+ clear();
+ disposalRestoreFromIdx = null;
+ lastDisposalMethod = null;
+ frame = null;
+ lastImg = null;
+
+ return true;
+ }
+
+ return {
+ // play controls
+ play: player.play,
+ pause: player.pause,
+ move_relative: player.move_relative,
+ move_to: player.move_to,
+
+ // getters for instance vars
+ get_playing : function() { return playing },
+ get_canvas : function() { return canvas },
+ get_canvas_scale : function() { return get_canvas_scale() },
+ get_loading : function() { return loading },
+ get_auto_play : function() { return options.auto_play },
+ get_length : function() { return player.length() },
+ get_current_frame: function() { return player.current_frame() },
+ load_url: function(src,callback){
+ if (!load_setup(callback)) return;
+
+ var h = new XMLHttpRequest();
+ // new browsers (XMLHttpRequest2-compliant)
+ h.open('GET', src, true);
+
+ if ('overrideMimeType' in h) {
+ h.overrideMimeType('text/plain; charset=x-user-defined');
+ }
+
+ // old browsers (XMLHttpRequest-compliant)
+ else if ('responseType' in h) {
+ h.responseType = 'arraybuffer';
+ }
+
+ // IE9 (Microsoft.XMLHTTP-compliant)
+ else {
+ h.setRequestHeader('Accept-Charset', 'x-user-defined');
+ }
+
+ h.onloadstart = function() {
+ // Wait until connection is opened to replace the gif element with a canvas to avoid a blank img
+ if (!initialized) init();
+ };
+ h.onload = function(e) {
+ if (this.status != 200) {
+ doLoadError('xhr - response');
+ }
+ // emulating response field for IE9
+ if (!('response' in this)) {
+ this.response = new VBArray(this.responseText).toArray().map(String.fromCharCode).join('');
+ }
+ var data = this.response;
+ if (data.toString().indexOf("ArrayBuffer") > 0) {
+ data = new Uint8Array(data);
+ }
+
+ stream = new Stream(data);
+ setTimeout(doParse, 0);
+ };
+ h.onprogress = function (e) {
+ if (e.lengthComputable) doShowProgress(e.loaded, e.total, true);
+ };
+ h.onerror = function() { doLoadError('xhr'); };
+ h.send();
+ },
+ load: function (callback) {
+ this.load_url(gif.getAttribute('rel:animated_src') || gif.src,callback);
+ },
+ load_raw: function(arr, callback) {
+ if (!load_setup(callback)) return;
+ if (!initialized) init();
+ stream = new Stream(arr);
+ setTimeout(doParse, 0);
+ },
+ set_frame_offset: setFrameOffset
+ };
+ };
+
+ return SuperGif;
+}));
+
+
diff --git a/pacotes/libgifjs/rubbable.js b/pacotes/libgifjs/rubbable.js
new file mode 100755
index 0000000..16a36b1
--- /dev/null
+++ b/pacotes/libgifjs/rubbable.js
@@ -0,0 +1,151 @@
+/*
+ RubbableGif
+
+ Example usage:
+
+
+
+
+
+ Image tag attributes:
+
+ rel:animated_src - If this url is specified, it's loaded into the player instead of src.
+ This allows a preview frame to be shown until animated gif data is streamed into the canvas
+
+ rel:auto_play - Defaults to 1 if not specified. If set to zero, the gif will be rubbable but will not
+ animate unless the user is rubbing it.
+
+ Constructor options args
+
+ gif Required. The DOM element of an img tag.
+ auto_play Optional. Same as the rel:auto_play attribute above, this arg overrides the img tag info.
+ max_width Optional. Scale images over max_width down to max_width. Helpful with mobile.
+
+ Instance methods
+
+ // loading
+ load( callback ) Loads the gif into a canvas element and then calls callback if one is passed
+
+ // play controls
+ play - Start playing the gif
+ pause - Stop playing the gif
+ move_to(i) - Move to frame i of the gif
+ move_relative(i) - Move i frames ahead (or behind if i < 0)
+
+ // getters
+ get_canvas The canvas element that the gif is playing in.
+ get_playing Whether or not the gif is currently playing
+ get_loading Whether or not the gif has finished loading/parsing
+ get_auto_play Whether or not the gif is set to play automatically
+ get_length The number of frames in the gif
+ get_current_frame The index of the currently displayed frame of the gif
+
+ For additional customization (viewport inside iframe) these params may be passed:
+ c_w, c_h - width and height of canvas
+ vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport
+
+*/
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(['./libgif'], factory);
+ } else if (typeof exports === 'object') {
+ module.exports = factory(require('./libgif'));
+ } else {
+ root.RubbableGif = factory(root.SuperGif);
+ }
+}(this, function (SuperGif) {
+ var RubbableGif = function( options ) {
+ var sup = new SuperGif( options );
+
+ var register_canvas_handers = function () {
+
+ var isvp = function(x) {
+ return (options.vp_l ? ( x - options.vp_l ) : x );
+ }
+
+ var canvas = sup.get_canvas();
+ var maxTime = 1000,
+ // allow movement if < 1000 ms (1 sec)
+ w = ( options.vp_w ? options.vp_w : canvas.width ),
+ maxDistance = Math.floor(w / (sup.get_length() * 2)),
+ // swipe movement of 50 pixels triggers the swipe
+ startX = 0,
+ startTime = 0;
+
+ var cantouch = "ontouchend" in document;
+
+ var aj = 0;
+ var last_played = 0;
+
+ canvas.addEventListener((cantouch) ? 'touchstart' : 'mousedown', function (e) {
+ // prevent image drag (Firefox)
+ e.preventDefault();
+ if (sup.get_auto_play()) sup.pause();
+
+ var pos = (e.touches && e.touches.length > 0) ? e.touches[0] : e;
+
+ var x = (pos.layerX > 0) ? isvp(pos.layerX) : w / 2;
+ var progress = x / w;
+
+ sup.move_to( Math.floor(progress * (sup.get_length() - 1)) );
+
+ startTime = e.timeStamp;
+ startX = isvp(pos.pageX);
+ });
+
+ canvas.addEventListener((cantouch) ? 'touchend' : 'mouseup', function (e) {
+ startTime = 0;
+ startX = 0;
+ if (sup.get_auto_play()) sup.play();
+ });
+
+ canvas.addEventListener((cantouch) ? 'touchmove' : 'mousemove', function (e) {
+ e.preventDefault();
+ var pos = (e.touches && e.touches.length > 0) ? e.touches[0] : e;
+
+ var currentX = isvp(pos.pageX);
+ currentDistance = (startX === 0) ? 0 : Math.abs(currentX - startX);
+ // allow if movement < 1 sec
+ currentTime = e.timeStamp;
+ if (startTime !== 0 && currentDistance > maxDistance) {
+ if (currentX < startX && sup.get_current_frame() > 0) {
+ sup.move_relative(-1);
+ }
+ if (currentX > startX && sup.get_current_frame() < sup.get_length() - 1) {
+ sup.move_relative(1);
+ }
+ startTime = e.timeStamp;
+ startX = isvp(pos.pageX);
+ }
+
+ var time_since_last_play = e.timeStamp - last_played;
+ {
+ aj++;
+ if (document.getElementById('tickles' + ((aj % 5) + 1))) document.getElementById('tickles' + ((aj % 5) + 1)).play();
+ last_played = e.timeStamp;
+ }
+
+
+ });
+ };
+
+ sup.orig_load = sup.load;
+ sup.load = function(callback) {
+ sup.orig_load( function() {
+ if (callback) callback();
+ register_canvas_handers( sup );
+ } );
+ }
+
+ return sup;
+ }
+
+ return RubbableGif;
+}));
\ No newline at end of file
--
libgit2 0.21.2