• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Njay

[Javascript] Mostrar dados de imagem codificados no nome da própria imagem

1 mensagem neste tópico

Quando era um "pro" de Javascript fiz esta página. Eu tinha um problema que era a catalogação das fotos de astronomia que tirava. É importante guardar com a foto meta-informação sobre as condições e material com que a foto foi tirada, e a que processamento digital foi sujeita. Comecei por escrever essa informação num ficheiro à parte, mas rapidamente se tornou numa chatice pois era feito à posteriori, e ainda por cima não tinha nenhum programa que me servisse para visualizar as fotos com a respectiva meta-informação. E depois ainda queria não só ver as fotos no meu PC como exportá-las, com a respectiva meta-info., para mostrar na web.

Resumindo, tinha 2 problemas:

1) a meta-informação não ficava "agarrada" à foto

2) não tinha forma simples (automática) de "exportar" as fotos para a web juntamente com essa meta-info.

Arranjei uma forma que me resolveu as 2 questões de uma vez só: passei a codificar a meta-informação no nome do próprio ficheiro. Depois criei uma página em Javascript que aceita o nome de um ficheiro imagem como argumento e mostra essa imagem mais a meta-informação codificada no nome da própria imagem. A mesma página, dando o parametro "mode=gen" permite gerar os nomes para as imagens, introduzindo os dados da mesma em formato inteligível.

Depois, em TCL, fiz um pequeno script que lê todas as imagens numa directoria e gera uma página HTML com links para mostrar a imagem mais a meta-informação (usando a mesma página Javascript mencionda anteriormente), isto para visualização no PC.

Mas bom, basta de conversa... para terem uma ideia concreta do que estou a falar, podem ver por exemplo uma das minhas imagens, mostrada com este código Javascript, aqui:

http://nsj.no.sapo.pt/astro/astrofotos/photoi.html?img=Saturn_401fo5s2ar2u3b100s25.jpg

Reparem no nome do argumento "img". É o nome do ficheiro com meta-info codificada.

Deixo aqui este código que, apesar de ser especifico para astronomia, pode ser adaptado para outras áreas, ou então sempre podem dar uma olhadela e usar algumas das funções ou outros pedaços. Deixo também o código TCL para verem como é grande.

Enjoy

A "super-página" codificadora/descodificadora de nomes de imagens: photoi.html

<html>
<head>
<title>Foto</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="-1">
<style>
	.AA  {font: bold italic 14px Arial helvetica, sans-serif; text-decoration: none; color:#999990; }
	.BB  {font: bold 14px Arial helvetica, sans-serif; text-decoration: none; color:#999990; }
	.MM  {font: bold 16px Arial helvetica, sans-serif; text-decoration: none; color:#EEEEEE; }
	.HLP {font: italic 14px Arial helvetica, sans-serif; text-decoration: none; color:#EEEEEE; }
	.MMT {font: bold 22px Arial helvetica, sans-serif; text-decoration: none; color:#EEEEEE; }
</style>

<script language="javascript">
// Quero a janela so' para mim!
if (top != window) top.location = location;
// Bye bye, pop-up chato! :>
var oldOpen = open;
function open() {}
</script>
</head>

<body bgcolor="#000000" text="#999990" link="#A8A8A0" vlink="#707070" alink="#809980">

<center>
<script language="Javascript">

// Copyright © Nuno Joao (nuno.joao[at]UPSportugalmail.pt, remove UPS)
// Licensed under GNU GPLv3

// Equipment Table
EquipTab = new Array();
EquipTabKeys = "ES";		// Must have all available table indexes
EquipTab['E'] = "ETX70, ToUCamPro";
EquipTab['S'] = "ETX70, Shorty+ 2x, ToUCamPro";

// Processing Software Table
SoftTab = new Array();
SoftTabKeys = "AIRFPSW";		// Must have all available table indexes
SoftTab['A'] = "Astrostack";
SoftTab['I'] = "Iris";
SoftTab['R'] = "Registax";
SoftTab['F'] = "PhotoLine";
SoftTab['P'] = "Paintshop Pro";
SoftTab['S'] = "PhotoShop";
SoftTab['W'] = "Windows Paint";

// Applied Effects / Extra Info Table
// $1 will be replaced by the argument given in the effect.
// Ex.: R3 -> $1 = 3 -> Resample 3x3
FxTab = new Array();
FxTabKeys = "ABCDHIJKLNRTUXFEGSM";	// Must have all available table indexes
FxTab['A'] = "Subtraction of dark mask"
FxTab['B'] = "Bias $1"
FxTab['C'] = "Contrast $1%";
FxTab['D'] = "DDP";
FxTab['H'] = "Histogram";
FxTab['I'] = "Convolution";
FxTab['J'] = "Cit Deconvolution $1x$1";
FxTab['K'] = "LR Deconvolution $1x$1";
FxTab['L'] = "Brightness $1%";
FxTab['N'] = "Color balance";
FxTab['R'] = "Resample $1x$1";
FxTab['T'] = "Threshold";
FxTab['U'] = "Unsharp mask $1x$1";
FxTab['X'] = "CLAHE $1x$1";
FxTab['F'] = "Adaptive blur filtering";
// Extra Info (note the '&' at the begining of the line)
FxTab['E'] = "&Exposition of $1s";
FxTab['G'] = "&Exposition of $1m";
FxTab['S'] = "&Exposition of 1/$1s";
FxTab['M'] = "&Mosaic of $1 photos";

// Some config vars
// With these values it reaches year 2101.
var StartYear = 1990;
var MaxDigits = 5;	// Date/time maximum number of digits

var UNK = "not available";
var UND = "undefined";


// ---< CODE START >--- //

// Debug function
function log(s)  { return;document.writeln('<font color="#FFFFFF"><code>'+ s +'</code></font><br>') }

// Get an argument from the url
function GetArg (name)  {
	var loc = location + "";
	var i1 = loc.indexOf(name + "=");
	if (i1 == -1)  return "";
	i1 += name.length +1;
	var i2 = loc.indexOf("&", i1);
	i2 += (i2 == -1)? loc.length+1: 0;
	return unescape(loc.substring(i1, i2));
}

// ---> Numbers base functions

var Base = 36.0;		// 36.0 is max supported; must be float
var Cod0 = "0".charCodeAt(0);
var CodA = "A".charCodeAt(0);

// Returns the arg as a float
function Mkf (n)  { return (n.toString().indexOf(".") == -1)? parseFloat(n + ".0"): n }

// Removes the fraccional part of a number
function Trunc (n)  {
	n += ".";
	m = n.substring(0, n.toString().indexOf("."));
	return m == ""? 0.0 : parseFloat(m, 10)
}

// Division modulus for big numbers.
// Argument must be float (use mkf) if number doesn't fit 32 bits
function Mod (a, b)  { return a - b * parseFloat(Trunc(Mkf(a / b)), 10) }

// Digit base 10 to base Base
function ToDigit (n)  { return String.fromCharCode(n + ((n > 9)? CodA - 10: Cod0)) }

// Digit base Base to base 10
function FromDigit (d)  { return d.charCodeAt(0) - (d > "9"? CodA - 10: Cod0) }

// Convert number in base 10 to base Base
function Base10toStd (n)  {
	var i, nbase = "";
	for (i = 0; i < MaxDigits; i++)  {
		//alert( "Mod(n,Base) = "+Mod(n, Base)+"\n"+"ToDigit(Mod(n, Base)) = " + ToDigit(Mod(n, Base)));
		nbase = ToDigit(Mod(n, Base)) + nbase;
		n = Trunc(Mkf(n / Base));
	}
	return nbase;
}

// Convert number in base Base to base 10
function BaseStdto10 (n)  {
	var i, d = 1.0, n10 = 0.0, t, numDig = n.length;
	for (n = n.toUpperCase(), i = 0; i < numDig; i++)  {
		t = FromDigit(n.charAt(numDig-i-1));
		n10 = n10 + t * d;
		d = d * Base;
	}
	return n10;
}

// ---> Date/Time functions

// Standard milliseconds to minutes from the start year
function Sm2mins (s)  {
	return (s - Date.UTC(StartYear,0,1,0,0,0)) / 1000 / 60
}

// Minutes from the start year to Date obj
function Mins2Date (i)  {
	if (typeof(i) != "number")  i = BaseStdto10(i);
	return new Date( i * 1000.0 * 60.0 + Date.UTC(StartYear,0,1,0,0,0) )
}

// ---> Image name parsing functions

// Assumes the image name is encoded
function GetImgInfo(str)  {	
	log("--- " + str + " ----------------------");
	// Set default values
	var info = new Array();
	info["str"] = str;
	info["uid"] = "";
	info["name"] = str;
	info["date"] = null;
	info["index"] = "";
	info["equip"] = UNK;
	info["number"] = 1;
	info["soft"] = UNK;
	info["fxs"] = null;
	// Name
	var i = str.indexOf("_"), i2, s;
	if (i == -1)  return null;	// wrong encoding
	info["name"] = str.substring(0, i++);
	if (str.length - i < 6)  return null;  // wrong encoding
	log("Name: " +info["name"]);
	// Date
	info["uid"] = str.substring(i, i+5).toUpperCase();	// this is only the 1st part of uid
	info["date"] = Mins2Date(info["uid"]);
	log("Date: " + info["date"].toGMTString());
	// Index
	info["index"] = str.charAt(i+5).toUpperCase();
	info["uid"] += info["index"];
	log("Index: " +info["index"]);
	if (i >= str.length) return null;	// wrong encoding
	// Equipment
	s = str.charAt(i+6).toUpperCase();
	if (typeof(EquipTab[s]) != UND)  info["equip"] = EquipTab[s];
	log("Equip: " +info["equip"]);
	i += 7;
	if (i >= str.length) return info;
	// Nº of images used (optional)
	for (i2 = i; str.charAt(i2) <= "9"; i2++);	// seek end of number
	if (i2 != i)  info["number"] = parseInt(str.substring(i, i2))
	log("Images #: " +info["number"]);
	i = i2;
	if (i >= str.length) return info;
	// Processing software
	s = str.charAt(i).toUpperCase();
	if (typeof(SoftTab[s]) != UND)  info["soft"] = SoftTab[s];
	log("Software: " +info["soft"]);
	i++;
	if (i >= str.length) return info;
	// Effects and extra info (optional and variable length)
	s = str.substring(i);
	var fxi = 0, fx = new Array(), eii = 0, ei = new Array();
	for (i = 0; i < s.length;)  {
		// First letter is effect
		var eff = s.charAt(i++).toUpperCase(), arg = "<default>";
		if (i < s.length)  {
			// If a number is available, is the argument
			for (i2 = i; (s.charAt(i2) <= "9") && (i2 < s.length); i2++);	// seek end of number
			arg = s.substring(i,i2);
			i = i2
		}
		if (typeof(FxTab[eff]) == UND)  return null;	// not an encoded name?...
		// Check if it is an extra info or effect
		if (FxTab[eff].charAt(0) == "&")  {
			ei[eii++] = FxTab[eff].substring(1).replace(/\$1/g, arg);
			log("  "+ eff +"("+ arg +") -> "+ ei[eii-1])
		}
		else  {
			fx[fxi++] = FxTab[eff].replace(/\$1/g, arg);
			log("  "+ eff +"("+ arg +") -> "+ fx[fxi-1])
		}
	}
	info["fxs"] = fx;
	info["eis"] = ei;
	log("GetImgInfo done - "+(info==null));
	return info
}

// Write the image information to the page
function ShowImgInfo(w,ifo)  {
	if (ifo == null) return;

	var d = w.document;
	d.writeln('<font color="#A0A090"><table border="0"><tr>');
	if (ifo["soft"] == UNK)  d.writeln('<td valign="top" align="center" width="347">');
	else  d.writeln('<td valign="top" align="right" width="347">');

	d.writeln("<h3>Dados Básicos / Basic Data</h3><b><span class=BB>");
	d.writeln(ifo["name"] + "<br>");
	//d.writeln("Unique Id is " + ifo["uid"].toUpperCase() + "<br>");
	if (ifo["date"])
		d.writeln(ifo["date"].toGMTString() + "<br>");
	d.writeln(ifo["equip"] + "<br>");
	if (typeof(ifo["eis"]) != UND)  {
		var eis = ifo["eis"];
		if (eis && eis.length > 0)
			for (var i = 0; i < eis.length; i++)
				d.writeln(eis[i] + "<br>");
	}
	d.writeln('</span></td>');

	if (ifo["soft"] != UNK)  {
		d.writeln('<td width="25"></td><td valign="top" width="347">');
		d.writeln("</b><h3>Processamento / Processing</h3><b><span class=BB>");
		d.writeln(ifo["soft"] + "<br>");
		d.writeln("Stacking of " + ifo["number"] + " image(s)<br>");
		if (typeof(ifo["fxs"]) != UND)  {
			var fxs = ifo["fxs"];
			if (fxs && fxs.length > 0)
				for (var i = 0; i < fxs.length; i++)  d.writeln("+ " + fxs[i] + "<br>");
		}
		d.writeln('</span></td>');
	}
	d.writeln('</tr></b></table></font>');
}

// ---> Show Image functions

function ShowMode()  {
	document.writeln("<br><br><br>");

	img = GetArg("img");
	if (img != "")  document.writeln('<img src="' + img + '" >');
	else  document.writeln('<br><b>Não foi dada nenhuma imagem para mostra<b><br>');
	//if (img != "")  document.images.img.src = img;

	document.writeln("<br><br><br>");

	if (img != "")  {
		// Extract the filename then decode and show the info
		var a1 = img.lastIndexOf("."), a2 = img.lastIndexOf("/");
		if (a1 != -1)  img = img.substring(0, a1);
		if (a2 != -1)  img = img.substring(a2 + 1);
		ShowImgInfo(window, GetImgInfo(img));
	}
}

// ---> Make Image Name functions

function MakeMode()  {
	var d = document, i, key, val;
	d.writeln('<br><span class=MMT>Gerador de nomes para astrofotografias</span><br><br>');
	d.writeln('<table><tr><td class=MM>');
	// Write the input form
	d.writeln('<form name="f">');
	d.writeln('Nome arbitrário <input type=text name=name size=20 value=Saturn></input><br>');
	//d.writeln('Data<br><input type=text name=date size=20 value="17/10/2002 00:00:00" onchange=GenName()></input><br>');
	d.writeln('<br>Data (hora local) ');
		var t = new Date();
		d.write('<input type=text name=day size=2 value=' +t.getDate() +'></input>');
		//d.writeln('/ <input type=text name=month size=2 value=10 onchange=GenName()></input>');
		d.writeln(' de <select name=month>');
		var MonthTab = ['Jan','Fev','Abr','Mar','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'];
		var a = new Date().getMonth();
		for (i = 0; i < MonthTab.length; i++)
			d.write('<option value=' + i + (i==a?' selected':'') +'>' + MonthTab[i] + '</option>');
		d.writeln('</select>');
		d.writeln(' de <input type=text name=year size=4 value=' +t.getFullYear() +'></input>');
		d.writeln(',  <input type=text name=hour size=2 value=00></input>');
		d.writeln(' h <input type=text name=min size=2 value=00></input> m<br>');
	d.writeln('<br>Indice (0 a 9 ou A a Z) <input type=text name=index size=1 value=0></input><br>');
	d.writeln('<br>Equipamento <select name=equip>');
		for (i = 0; i < EquipTabKeys.length; i++)  {
			key = EquipTabKeys.charAt(i);
			d.write('<option value=' +key+ '>' +EquipTab[key] +'</option>');
		}
		d.writeln('</select><br>');
	d.writeln('<br>Nº de imagens "stacked" <input type=text name=num size=4 value=1></input><br>');
	d.writeln('<br>Software de processamento <select name=soft>');
		for (i = 0; i < SoftTabKeys.length; i++)  {
			key = SoftTabKeys.charAt(i);
			d.write('<option value=' + key + '>' + SoftTab[key] + '</option>');
		}
		d.writeln('</select><br>');
	d.writeln('<br><hr>');
	d.writeln('<br>Efeitos / Informação Extra <select name=fxs onchange=AddFx()>');
	d.writeln('<option value="" selected>- Adicionar -</option>');
		for (i = 0; i < FxTabKeys.length; i++)  {
			key = FxTabKeys.charAt(i);
			val = FxTab[key].replace(/\$1/ig, "N").replace(/\&/, "");
			d.write('<option value=' + key + '>' + val + '</option>');
		}
		d.writeln('</select>  N: <input type=text name=N size=6></input><br>');

	d.writeln('<br><hr>');
	d.writeln('<br>NOME GERADO<br><input type=text name=iname size=26></input>');
	d.writeln('  <input type=button value="Gerar Nome Base" onclick=GenName()></input><br>');
	d.writeln('</form>');
	d.writeln('<td></tr></table>');
	// help
	d.writeln('<table width=80%><tr><td class=HLP>');
	d.writeln('Primeiro escolhem-se todos os dados á excepçáo dos efeitos e gera-se o nome base');
	d.writeln('(usando o botão). Depois podem-se adicionar vários efeitos, 1 a 1. Sempre que se ');
	d.writeln('gera o nome base, todos os efeitos previamente adicionados são removidos.<br><br>');
	d.writeln('<td></tr></table>');
}

// Generate the base name from the form data
function GenName()  {
	var f = document.forms.f, name, d, um;
	d = new Date(f.year.value, f.month.options[f.month.selectedIndex].value,
	             f.day.value, f.hour.value, f.min.value);
	um = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(),
	              d.getUTCHours(), d.getUTCMinutes());
	name = Base10toStd(Sm2mins(um)) + f.index.value +
	       f.equip.options[f.equip.selectedIndex].value;
	delete d;
	d = f.num.value;
	name += (d=='1' || d==''? '': d) + f.soft.options[f.soft.selectedIndex].value;
	f.iname.value = f.name.value + "_" + name.toLowerCase();	// show the result
}

// Add an effect / extra-info to the already generated name
function AddFx()  {
	var f = document.forms.f, key;
	key = f.fxs.options[f.fxs.selectedIndex].value;
	if (FxTab[key].search(/\$1/i) < 0)  f.iname.value += key.toLowerCase();
	else
		if (f.N.value != "")  f.iname.value += key.toLowerCase() + f.N.value;
		else alert("Este efeito precisa de um valor para N  ");
	f.fxs.selectedIndex = 0;	// automatically select the first item
}


// ---> Startup

//MakeMode();

if (GetArg("mode") == "gen")  MakeMode();  else  ShowMode()

</script>

<br>
<font size="-2"><a href="javascript:history.back()"><b>Voltar / Back</b><br><br></a></font>
<i>Copyright © 2002-2006 <a href="mailto:Nuno-Joao@PortugalUPSmail.pt?subject=Vi%20a%20foto%20e%20acho%20que..."> Nuno João</a><br><font size="-1">(apaga o UPS do email / delete UPS from email)</font></i>

</center>

</body>
</html>

Script TCL para gerar uma página de "indíce" das imagens na directoria actual: genIndex.tcl

set photo_page "photoi.html"

file copy -force -- $photo_page photoi.html

set fd [open iindex.html w]
puts $fd "<html><head><title>Indice de imagens</title></head><body>"
puts $fd "<h2>Lista de imagens</h2>"


set i 0
foreach mask {*.bmp *.jpg *.png}  {
foreach img [lsort [glob -nocomplain $mask]]  {
	puts $fd "<a href=\"photoi.html?img=$img\">[incr i] - $img</a><br>"
}
}

puts $fd "</body></html>"
close $fd

puts "Done."

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora