mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2026-08-03 09:21:40 -07:00
wip: image format inference, avm parser based on https://www.strudel.org.uk/avm/js/, wcs creation from avm tags
This commit is contained in:
committed by
Matthieu Baumann
parent
4baab48716
commit
c42002db8f
@@ -14,7 +14,7 @@
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin('#aladin-lite-div', {target: "05 40 59.12 -02 27 04.1", fov: 2});
|
||||
|
||||
let survey = aladin.createImageSurvey('DSS2 local', "local hips", "hips/CDS_P_DSS2_color");
|
||||
let survey = aladin.createImageSurvey('DSS2 local', "local hips", "./hips/CDS_P_DSS2_color");
|
||||
aladin.setBaseImageLayer(survey);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
|
||||
<script type="module">
|
||||
import A from '../src/js/A.js';
|
||||
A.init.then(() => {
|
||||
let aladin = A.aladin('#aladin-lite-div', {fov: 30, survey: "CDS/P/PanSTARRS/DR1/color-z-zg-g", target: "280 +0", projection: "AIT", showShareControl:true, showSettingsControl: true, showContextMenu:true});
|
||||
|
||||
aladin.setOverlayImageLayer(A.image(
|
||||
//"https://www.virtualastronomy.org/images/sig05-013.jpg",
|
||||
"https://www.astropix.org/archive/eso/eso0755a/eso_eso0755a_1280.jpg",
|
||||
{
|
||||
name: "sig05-017",
|
||||
successCallback: (ra, dec, fov, image) => {
|
||||
console.log(ra, dec)
|
||||
aladin.gotoRaDec(ra, dec);
|
||||
aladin.setFoV(fov * 5)
|
||||
}
|
||||
},
|
||||
));
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -13,7 +13,6 @@
|
||||
"https://nova.astrometry.net/image/25038473?filename=M61.jpg",
|
||||
{
|
||||
name: "M61",
|
||||
imgFormat: 'jpeg',
|
||||
wcs: {
|
||||
NAXIS: 0, // Minimal header
|
||||
CTYPE1: 'RA---TAN', // TAN (gnomic) projection
|
||||
|
||||
+3
-2
@@ -1115,7 +1115,6 @@ impl App {
|
||||
|
||||
pub(crate) fn add_image_fits(
|
||||
&mut self,
|
||||
id: String,
|
||||
stream: web_sys::ReadableStream,
|
||||
meta: ImageMetadata,
|
||||
layer: String,
|
||||
@@ -1245,8 +1244,9 @@ impl App {
|
||||
} else {
|
||||
let fits = ImageLayer {
|
||||
images,
|
||||
id: layer.clone(),
|
||||
|
||||
layer,
|
||||
id,
|
||||
meta,
|
||||
};
|
||||
|
||||
@@ -1301,6 +1301,7 @@ impl App {
|
||||
) -> Result<(), JsValue> {
|
||||
let old_meta = self.layers.get_layer_cfg(&layer)?;
|
||||
// Set the new meta
|
||||
// keep the old meta data
|
||||
let new_img_fmt = meta.img_format;
|
||||
self.layers
|
||||
.set_layer_cfg(layer.clone(), meta, &mut self.camera, &self.projection)?;
|
||||
|
||||
+3
-5
@@ -382,21 +382,19 @@ impl WebClient {
|
||||
#[wasm_bindgen(js_name = addImageFITS)]
|
||||
pub fn add_image_fits(
|
||||
&mut self,
|
||||
id: String,
|
||||
stream: web_sys::ReadableStream,
|
||||
cfg: JsValue,
|
||||
layer: String,
|
||||
) -> Result<js_sys::Promise, JsValue> {
|
||||
let cfg: ImageMetadata = serde_wasm_bindgen::from_value(cfg)?;
|
||||
//let wcs: Option<WCSParams> = serde_wasm_bindgen::from_value(wcs)?;
|
||||
|
||||
self.app.add_image_fits(id, stream, cfg, layer)
|
||||
self.app.add_image_fits(stream, cfg, layer)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = addImageWithWCS)]
|
||||
pub fn add_image_with_wcs(
|
||||
&mut self,
|
||||
data: web_sys::ReadableStream,
|
||||
stream: web_sys::ReadableStream,
|
||||
wcs: JsValue,
|
||||
cfg: JsValue,
|
||||
layer: String,
|
||||
@@ -406,7 +404,7 @@ impl WebClient {
|
||||
let wcs_params: WCSParams = serde_wasm_bindgen::from_value(wcs)?;
|
||||
let wcs = WCS::new(&wcs_params).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?;
|
||||
|
||||
self.app.add_image_from_blob_and_wcs(layer, data, wcs, cfg)
|
||||
self.app.add_image_from_blob_and_wcs(layer, stream, wcs, cfg)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = removeLayer)]
|
||||
|
||||
+175
-80
@@ -28,6 +28,9 @@
|
||||
import { ALEvent } from "./events/ALEvent.js";
|
||||
import { ColorCfg } from "./ColorCfg.js";
|
||||
import { Aladin } from "./Aladin.js";
|
||||
import { Utils } from "./Utils";
|
||||
import { AVM } from "./libs/avm.js";
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} ImageOptions
|
||||
@@ -48,7 +51,7 @@ import { Aladin } from "./Aladin.js";
|
||||
* @property {number} [contrast=0.0] - The contrast value for the color configuration.
|
||||
* @property {Object} [wcs] - an object describing the WCS of the image. In case of a fits image
|
||||
* this property will be ignored as the WCS taken will be the one present in the fits file.
|
||||
* @property {number} [imgFormat='fits'] - The image format of the image to load.
|
||||
* @property {string} [imgFormat] - Optional image format. Giving it will prevent the auto extension determination algorithm to be triggered. Possible values are 'jpeg', 'png' or 'fits'.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
@@ -56,7 +59,6 @@ import { Aladin } from "./Aladin.js";
|
||||
* "https://nova.astrometry.net/image/25038473?filename=M61.jpg",
|
||||
* {
|
||||
* name: "M61",
|
||||
* imgFormat: 'jpeg',
|
||||
* wcs: {
|
||||
* NAXIS: 0, // Minimal header
|
||||
* CTYPE1: 'RA---TAN', // TAN (gnomic) projection + SIP distortions
|
||||
@@ -104,8 +106,8 @@ export let Image = (function () {
|
||||
this.url = url;
|
||||
this.id = url;
|
||||
this.name = (options && options.name) || this.url;
|
||||
this.imgFormat = (options && options.imgFormat) || "fits";
|
||||
this.formats = [this.imgFormat];
|
||||
this.imgFormat = options && options.imgFormat;
|
||||
//this.formats = [this.imgFormat];
|
||||
// callbacks
|
||||
this.successCallback = options && options.successCallback;
|
||||
this.errorCallback = options && options.errorCallback;
|
||||
@@ -116,7 +118,7 @@ export let Image = (function () {
|
||||
}*/
|
||||
|
||||
this.colorCfg = new ColorCfg(options);
|
||||
this.options = options;
|
||||
this.options = options || {};
|
||||
|
||||
let self = this;
|
||||
|
||||
@@ -219,92 +221,185 @@ export let Image = (function () {
|
||||
}
|
||||
};
|
||||
|
||||
Image.prototype._addFITS = function(layer) {
|
||||
let self = this;
|
||||
|
||||
return Utils.fetch({
|
||||
url: this.url,
|
||||
dataType: 'readableStream',
|
||||
success: (stream) => {
|
||||
return self.view.wasm.addImageFITS(
|
||||
stream,
|
||||
{
|
||||
...self.colorCfg.get(),
|
||||
longitudeReversed: false,
|
||||
imgFormat: 'fits',
|
||||
},
|
||||
layer
|
||||
);
|
||||
}
|
||||
})
|
||||
.then((imageParams) => {
|
||||
self.imgFormat = 'fits';
|
||||
|
||||
return Promise.resolve(imageParams);
|
||||
});
|
||||
}
|
||||
|
||||
Image.prototype._addJPGOrPNG = function(layer) {
|
||||
let self = this;
|
||||
let img = document.createElement('img');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
img.src = this.url;
|
||||
img.crossOrigin = "Anonymous";
|
||||
img.onload = () => {
|
||||
const img2Blob = () => {
|
||||
var canvas = document.createElement("canvas");
|
||||
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
// Copy the image contents to the canvas
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(img, 0, 0, img.width, img.height);
|
||||
|
||||
const imageData = ctx.getImageData(0, 0, img.width, img.height);
|
||||
|
||||
const blob = new Blob([imageData.data]);
|
||||
const stream = blob.stream(1024);
|
||||
|
||||
console.log(self.options, stream)
|
||||
|
||||
|
||||
resolve(stream)
|
||||
};
|
||||
|
||||
if (!self.options.wcs) {
|
||||
/* look for avm tags if no wcs is given */
|
||||
let avm = new AVM(img);
|
||||
console.log(img.complete)
|
||||
avm.load((obj) => {
|
||||
// obj contains the following information:
|
||||
// obj.id (string) = The ID provided for the image
|
||||
// obj.img (object) = The image object
|
||||
// obj.xmp (string) = The raw XMP header
|
||||
// obj.avmdata (Boolean) = If AVM tags have been loaded
|
||||
// obj.tags (object) = An array containing all the loaded tags e.g. obj.tags['Headline']
|
||||
console.log(obj)
|
||||
|
||||
if (obj.avmdata) {
|
||||
let wcs = {};
|
||||
wcs.CTYPE1 = obj.tags['Spatial.CoordinateFrame'] === 'ICRS' ? 'RA---' : 'GLON-';
|
||||
wcs.CTYPE1 += obj.tags['Spatial.CoordsystemProjection'];
|
||||
wcs.CTYPE2 = obj.tags['Spatial.CoordinateFrame'] === 'ICRS' ? 'DEC--' : 'GLAT-';
|
||||
wcs.CTYPE2 += obj.tags['Spatial.CoordsystemProjection'];
|
||||
|
||||
if (obj.tags['Spatial.Equinox'])
|
||||
wcs.EQUINOX = +obj.tags['Spatial.Equinox'];
|
||||
|
||||
wcs.NAXIS1 = +obj.tags['Spatial.ReferenceDimension'][0];
|
||||
wcs.NAXIS2 = +obj.tags['Spatial.ReferenceDimension'][1];
|
||||
|
||||
wcs.CDELT1 = +obj.tags['Spatial.Scale'][0];
|
||||
wcs.CDELT2 = +obj.tags['Spatial.Scale'][1];
|
||||
|
||||
wcs.CRPIX1 = +obj.tags['Spatial.ReferencePixel'][0];
|
||||
wcs.CRPIX2 = +obj.tags['Spatial.ReferencePixel'][1];
|
||||
|
||||
wcs.CRVAL1 = +obj.tags['Spatial.ReferenceValue'][0];
|
||||
wcs.CRVAL2 = +obj.tags['Spatial.ReferenceValue'][1];
|
||||
|
||||
if (obj.tags['Spatial.Rotation'] !== undefined)
|
||||
wcs.CROTA2 = +obj.tags['Spatial.Rotation'];
|
||||
|
||||
self.options.wcs = wcs;
|
||||
|
||||
img2Blob()
|
||||
} else {
|
||||
// no tags found
|
||||
reject('No AVM tags have been found in the image')
|
||||
return;
|
||||
}
|
||||
|
||||
})
|
||||
} else {
|
||||
img2Blob()
|
||||
}
|
||||
}
|
||||
|
||||
let proxyUsed = false;
|
||||
img.onerror = () => {
|
||||
// use proxy
|
||||
if (proxyUsed) {
|
||||
reject('Error parsing img ' + self.url)
|
||||
return;
|
||||
}
|
||||
|
||||
proxyUsed = true;
|
||||
img.src = Aladin.JSONP_PROXY + '?url=' + self.url;
|
||||
}
|
||||
})
|
||||
.then((readableStream) => {
|
||||
let wcs = self.options && self.options.wcs;
|
||||
wcs.NAXIS1 = wcs.NAXIS1 || img.width;
|
||||
wcs.NAXIS2 = wcs.NAXIS2 || img.height;
|
||||
|
||||
return self.view.wasm
|
||||
.addImageWithWCS(
|
||||
readableStream,
|
||||
wcs,
|
||||
{
|
||||
...self.colorCfg.get(),
|
||||
longitudeReversed: false,
|
||||
imgFormat: 'jpeg',
|
||||
},
|
||||
layer
|
||||
)
|
||||
})
|
||||
.then((imageParams) => {
|
||||
self.imgFormat = 'jpeg';
|
||||
return Promise.resolve(imageParams);
|
||||
})
|
||||
.finally(() => {
|
||||
img.remove();
|
||||
});
|
||||
}
|
||||
|
||||
Image.prototype.add = function (layer) {
|
||||
this.layer = layer;
|
||||
|
||||
let self = this;
|
||||
|
||||
let promise;
|
||||
|
||||
if (this.imgFormat === 'fits') {
|
||||
let id = this.url;
|
||||
promise = fetch(this.url)
|
||||
.then((resp) => resp.body)
|
||||
.then((readableStream) => {
|
||||
return self.view.wasm
|
||||
.addImageFITS(
|
||||
id,
|
||||
readableStream,
|
||||
{
|
||||
...self.colorCfg.get(),
|
||||
longitudeReversed: false,
|
||||
imgFormat: self.imgFormat,
|
||||
},
|
||||
layer
|
||||
)
|
||||
promise = this._addFITS(layer)
|
||||
.catch(e => {
|
||||
console.error(`Image located at ${this.url} could not be parsed as fits file. Is the imgFormat specified correct?`)
|
||||
return Promise.reject(e)
|
||||
})
|
||||
} else if (this.imgFormat === 'jpg' || this.imgFormat === 'jpeg') {
|
||||
let img = document.createElement('img');
|
||||
|
||||
promise =
|
||||
new Promise((resolve, reject) => {
|
||||
img.src = this.url;
|
||||
img.crossOrigin = "Anonymous";
|
||||
img.onload = () => {
|
||||
var canvas = document.createElement("canvas");
|
||||
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
// Copy the image contents to the canvas
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(img, 0, 0, img.width, img.height);
|
||||
|
||||
const imageData = ctx.getImageData(0, 0, img.width, img.height);
|
||||
|
||||
const blob = new Blob([imageData.data]);
|
||||
const stream = blob.stream(1024);
|
||||
|
||||
resolve(stream)
|
||||
}
|
||||
|
||||
let proxyUsed = false;
|
||||
img.onerror = () => {
|
||||
// use proxy
|
||||
if (proxyUsed) {
|
||||
reject('Error parsing img ' + self.url)
|
||||
return;
|
||||
}
|
||||
|
||||
proxyUsed = true;
|
||||
img.src = Aladin.JSONP_PROXY + '?url=' + self.url;
|
||||
}
|
||||
})
|
||||
.then((readableStream) => {
|
||||
let wcs = self.options && self.options.wcs;
|
||||
wcs.NAXIS1 = wcs.NAXIS1 || img.width;
|
||||
wcs.NAXIS2 = wcs.NAXIS2 || img.height;
|
||||
|
||||
return self.view.wasm
|
||||
.addImageWithWCS(
|
||||
readableStream,
|
||||
wcs,
|
||||
{
|
||||
...self.colorCfg.get(),
|
||||
longitudeReversed: false,
|
||||
imgFormat: self.imgFormat,
|
||||
},
|
||||
layer
|
||||
)
|
||||
})
|
||||
.finally(() => {
|
||||
img.remove();
|
||||
} else if (this.imgFormat === 'jpeg' || this.imgFormat === 'png') {
|
||||
promise = this._addJPGOrPNG(layer)
|
||||
.catch(e => {
|
||||
console.error(`Image located at ${this.url} could not be parsed as a ${this.imgFormat} file. Is the imgFormat specified correct?`);
|
||||
return Promise.reject(e)
|
||||
})
|
||||
} else {
|
||||
console.warn(`Image format: ${this.imgFormat} not supported`);
|
||||
promise = Promise.reject();
|
||||
};
|
||||
// imgformat not defined we will try first supposing it is a fits file and then use the jpg heuristic
|
||||
promise = this._addFITS(layer)
|
||||
.catch(_ => {
|
||||
console.warn(`Image located at ${self.url} could not be parsed as fits file. Try as a jpg/png image...`)
|
||||
return self._addJPGOrPNG(layer)
|
||||
.catch(e => {
|
||||
console.error(`Image located at ${self.url} could not be parsed as jpg/png image file. Aborting...`)
|
||||
return Promise.reject(e);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
promise = promise.then((imageParams) => {
|
||||
self.formats = [self.imgFormat];
|
||||
|
||||
// There is at least one entry in imageParams
|
||||
self.added = true;
|
||||
self.setView(self.view);
|
||||
|
||||
@@ -381,6 +381,8 @@ Utils.fetch = function(params) {
|
||||
return resp.json()
|
||||
} else if (params.dataType && params.dataType.includes('blob')) {
|
||||
return resp.blob()
|
||||
} else if (params.dataType && params.dataType.includes('readableStream')) {
|
||||
return resp.body;
|
||||
} else {
|
||||
return resp.text()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Javascript AVM/XMP Reader 0.1.3
|
||||
* Copyright (c) 2010 Stuart Lowe http://www.strudel.org.uk/
|
||||
* Astronomy Visualization Metadata (AVM) is defined at:
|
||||
* http://www.virtualastronomy.org/avm_metadata.php
|
||||
*
|
||||
* Licensed under the MPL http://www.mozilla.org/MPL/MPL-1.1.txt
|
||||
*
|
||||
*/
|
||||
|
||||
export let AVM = (function() {
|
||||
|
||||
function AVM(input) {
|
||||
if (input instanceof HTMLImageElement) {
|
||||
this.img = input;
|
||||
} else {
|
||||
// suppose that input is a string
|
||||
this.id = (input) ? input : "";
|
||||
this.img = { complete: false };
|
||||
}
|
||||
|
||||
this.xmp = ""; // Will hold the XMP string (for test purposes)
|
||||
this.avmdata = false;
|
||||
this.tags = {}
|
||||
this.AVMdefinedTags = {
|
||||
'Creator':'photoshop:Source',
|
||||
'CreatorURL':'Iptc4xmpCore:CiUrlWork',
|
||||
'Contact.Name':'dc:creator',
|
||||
'Contact.Email':'Iptc4xmpCore:CiEmailWork',
|
||||
'Contact.Telephone':'Iptc4xmpCore:CiTelWork',
|
||||
'Contact.Address':'Iptc4xmpCore:CiAdrExtadr',
|
||||
'Contact.City':'Iptc4xmpCore:CiAdrCity',
|
||||
'Contact.StateProvince':'Iptc4xmpCore:CiAdrRegion',
|
||||
'Contact.PostalCode':'Iptc4xmpCore:CiAdrPcode',
|
||||
'Contact.Country':'Iptc4xmpCore:CiAdrCtry',
|
||||
'Rights':'xapRights:UsageTerms',
|
||||
'Title':'dc:title',
|
||||
'Headline':'photoshop:Headline',
|
||||
'Description':'dc:description',
|
||||
'Subject.Category':'avm:Subject.Category',
|
||||
'Subject.Name':'dc:subject',
|
||||
'Distance':'avm:Distance',
|
||||
'Distance.Notes':'avm:Distance.Notes',
|
||||
'ReferenceURL':'avm:ReferenceURL',
|
||||
'Credit':'photoshop:Credit',
|
||||
'Date':'photoshop:DateCreated',
|
||||
'ID':'avm:ID',
|
||||
'Type':'avm:Type',
|
||||
'Image.ProductQuality':'avm:Image.ProductQuality',
|
||||
'Facility':'avm:Facility',
|
||||
'Instrument':'avm:Instrument',
|
||||
'Spectral.ColorAssignment':'avm:Spectral.ColorAssignment',
|
||||
'Spectral.Band':'avm:Spectral.Band',
|
||||
'Spectral.Bandpass':'avm:Spectral.Bandpass',
|
||||
'Spectral.CentralWavelength':'avm:Spectral.CentralWavelength',
|
||||
'Spectral.Notes':'avm:Spectral.Notes',
|
||||
'Temporal.StartTime':'avm:Temporal.StartTime',
|
||||
'Temporal.IntegrationTime':'avm:Temporal.IntegrationTime',
|
||||
'DatasetID':'avm:DatasetID',
|
||||
'Spatial.CoordinateFrame':'avm:Spatial.CoordinateFrame',
|
||||
'Spatial.Equinox':'avm:Spatial.Equinox',
|
||||
'Spatial.ReferenceValue':'avm:Spatial.ReferenceValue',
|
||||
'Spatial.ReferenceDimension':'avm:Spatial.ReferenceDimension',
|
||||
'Spatial.ReferencePixel':'avm:Spatial.ReferencePixel',
|
||||
'Spatial.Scale':'avm:Spatial.Scale',
|
||||
'Spatial.Rotation':'avm:Spatial.Rotation',
|
||||
'Spatial.CoordsystemProjection':'avm:Spatial.CoordsystemProjection',
|
||||
'Spatial.Quality':'avm:Spatial.Quality',
|
||||
'Spatial.Notes':'avm:Spatial.Notes',
|
||||
'Spatial.FITSheader':'avm:Spatial.FITSheader',
|
||||
'Spatial.CDMatrix':'avm:Spatial.CDMatrix',
|
||||
'Publisher':'avm:Publisher',
|
||||
'PublisherID':'avm:PublisherID',
|
||||
'ResourceID':'avm:ResourceID',
|
||||
'ResourceURL':'avm:ResourceURL',
|
||||
'RelatedResources':'avm:RelatedResources',
|
||||
'MetadataDate':'avm:MetadataDate',
|
||||
'MetadataVersion':'avm:MetadataVersion'
|
||||
}
|
||||
}
|
||||
|
||||
AVM.prototype.load = function(fnCallback) {
|
||||
if(!this.img && this.id) {
|
||||
this.img = document.getElementById(this.id);
|
||||
}
|
||||
|
||||
if(!this.img.complete) {
|
||||
var _obj = this;
|
||||
addEvent(this.img, "load",
|
||||
function() {
|
||||
_obj.getData(fnCallback);
|
||||
}
|
||||
);
|
||||
}else{
|
||||
this.getData(fnCallback);
|
||||
}
|
||||
}
|
||||
|
||||
AVM.prototype.getData = function(fnCallback){
|
||||
if(!this.imageHasData()){
|
||||
this.getImageData(this.img, fnCallback);
|
||||
}else{
|
||||
if(typeof fnCallback=="function") fnCallback(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AVM.prototype.getImageData = function(oImg, fnCallback) {
|
||||
var _obj = this;
|
||||
let reqwst = new Request(oImg.src, {
|
||||
method: 'GET',
|
||||
})
|
||||
fetch(reqwst)
|
||||
.then((resp) => resp.arrayBuffer())
|
||||
.then(arrayBuffer => {
|
||||
const view = new DataView(arrayBuffer);
|
||||
var oAVM = _obj.findAVMinJPEG(view);
|
||||
_obj.avmdata = true;
|
||||
_obj.tags = oAVM || {};
|
||||
if (typeof fnCallback=="function") fnCallback(_obj);
|
||||
})
|
||||
}
|
||||
|
||||
function addEvent(oElement, strEvent, fncHandler){
|
||||
if (oElement.addEventListener) oElement.addEventListener(strEvent, fncHandler, false);
|
||||
else if (oElement.attachEvent) oElement.attachEvent("on" + strEvent, fncHandler);
|
||||
}
|
||||
|
||||
AVM.prototype.imageHasData = function() {
|
||||
return (this.img.avmdata);
|
||||
}
|
||||
|
||||
AVM.prototype.findAVMinJPEG = function(oFile) {
|
||||
if (oFile.getUint8(0) != 0xFF || oFile.getUint8(1) != 0xD8) return false; // not a valid jpeg
|
||||
|
||||
var iOffset = 2;
|
||||
var iLength = oFile.byteLength;
|
||||
while (iOffset < iLength) {
|
||||
if (oFile.getUint8(iOffset) != 0xFF) return false; // not a valid marker, something is wrong
|
||||
var iMarker = oFile.getUint8(iOffset+1)+1;
|
||||
|
||||
|
||||
// we could implement handling for other markers here,
|
||||
// but we're only looking for 0xFFE1 for AVM data
|
||||
if (iMarker == 22400) {
|
||||
return this.readAVMData(oFile, iOffset + 4, oFile.getUint16(iOffset+2, false)-2);
|
||||
iOffset += 2 + oFile.getUint16(iOffset+2, false);
|
||||
|
||||
} else if (iMarker == 225) {
|
||||
// 0xE1 = Application-specific 1 (for AVM)
|
||||
console.log("jkjk")
|
||||
var oTags = this.readAVMData(oFile, iOffset + 4, oFile.getUint16(iOffset+2, false)-2);
|
||||
return oTags;
|
||||
} else {
|
||||
iOffset += 2 + oFile.getUint16(iOffset+2, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AVM.prototype.readAVMData = function(oFile, iStart, iLength){
|
||||
var oTags = {};
|
||||
this.xmp = this.readXMP(oFile);
|
||||
console.log("xmp read", this.xmp)
|
||||
if (this.xmp) oTags = this.readAVM(this.xmp);
|
||||
return oTags;
|
||||
}
|
||||
|
||||
AVM.prototype.readXMP = function(oFile) {
|
||||
var iEntries = oFile.byteLength;
|
||||
var bBigEnd = false;
|
||||
var prev_n_hex = '';
|
||||
var record = false;
|
||||
var recordn = 0;
|
||||
// Find the XMP packet - 8 bit encoding (UTF-8)
|
||||
// see page 34 of http://www.adobe.com/devnet/xmp/pdfs/xmp_specification.pdf
|
||||
var xmpStr = '0x3C 0x3F 0x78 0x70 0x61 0x63 0x6B 0x65 0x74 0x20 0x62 0x65 0x67 0x69 0x6E 0x3D ';
|
||||
var xmpBytes = 14;
|
||||
var byteStr = '';
|
||||
var iEntryOffset = -1;
|
||||
console.log(iEntryOffset)
|
||||
|
||||
// Here we want to search for the XMP packet starting string
|
||||
// There is probably a more efficient way to search for a byte string
|
||||
for (var i=0;i<iEntries;i++) {
|
||||
|
||||
var n = oFile.getUint8(i);
|
||||
var n_hex = n.toString(16).toUpperCase();
|
||||
if(n_hex.length == 1) n_hex = "0x0"+n_hex;
|
||||
if(n_hex.length == 2) n_hex = "0x"+n_hex;
|
||||
|
||||
if(prev_n_hex == "0x3C" && n_hex == "0x3F"){
|
||||
record = true;
|
||||
recordn = xmpBytes;
|
||||
byteStr = '0x3C ';
|
||||
}
|
||||
if(record){
|
||||
byteStr += n_hex+' ';
|
||||
console.log(byteStr, recordn)
|
||||
|
||||
recordn--;
|
||||
if(recordn < 0){
|
||||
if(byteStr == xmpStr){
|
||||
var iEntryOffset = i-xmpBytes-1;
|
||||
break;
|
||||
}
|
||||
record = false;
|
||||
}
|
||||
}
|
||||
prev_n_hex = n_hex;
|
||||
}
|
||||
console.log(iEntryOffset)
|
||||
if(iEntryOffset >= 0){
|
||||
var str = '';
|
||||
var i = iEntryOffset;
|
||||
while(str.indexOf('</x:xmpmeta>') < 0 && i < (iEntryOffset+20000)){
|
||||
str += String.fromCharCode(oFile.getUint8(i));
|
||||
i++;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
AVM.prototype.readAVM = function(str) {
|
||||
var oTags = {};
|
||||
if(str.indexOf('xmlns:avm') >= 0){
|
||||
for (var keyname in this.AVMdefinedTags) {
|
||||
var key = this.AVMdefinedTags[keyname];
|
||||
key.toLowerCase();
|
||||
var start = str.indexOf(key)+key.length+2;
|
||||
var final = str.indexOf('"',start);
|
||||
// Find out what the character is after the key
|
||||
var char = str.substring(start-2,start-1);
|
||||
if(char == "="){
|
||||
oTags[keyname] = str.substring(start,final);
|
||||
}else if(char == ">"){
|
||||
final = str.indexOf('</'+key+'>',start);
|
||||
// Parse out the HTML tags and build an array of the resulting values
|
||||
var tmps = str.substring(start-1,final);
|
||||
console.log(tmps)
|
||||
var tmparr = new Array(0);
|
||||
var tmpstr = tmps.replace(/[\n\r]/g,"");
|
||||
tmpstr = tmpstr.replace(/ +/g," ");
|
||||
tmparr = tmpstr.split(/ ?<\/?[^>]+> ?/g);
|
||||
var newarr = new Array(0);
|
||||
for(var i = 0;i<tmparr.length;i++){
|
||||
if(tmparr[i].length > 0) newarr.push(tmparr[i]);
|
||||
}
|
||||
oTags[keyname] = newarr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return oTags;
|
||||
}
|
||||
|
||||
return AVM;
|
||||
})();
|
||||
Reference in New Issue
Block a user