2
require_once('DbConnection.php');
4
abstract class JP2Image {
5
protected $kdu_expand = CONFIG::KDU_EXPAND;
6
protected $kdu_lib_path = CONFIG::KDU_LIBS_DIR;
7
protected $cacheDir = CONFIG::CACHE_DIR;
8
protected $jp2Dir = CONFIG::JP2_DIR;
9
protected $noImage = CONFIG::EMPTY_TILE;
10
protected $baseScale = 2.63; //Scale of an EIT image at the base zoom-level: 2.63 arcseconds/px
11
protected $baseZoom = 10; //Zoom-level at which (EIT) images are of this scale.
18
protected $desiredScale;
22
protected function __construct($zoomLevel, $xRange, $yRange, $tileSize) {
23
date_default_timezone_set('UTC');
24
$this->db = new DbConnection();
25
$this->zoomLevel = $zoomLevel;
26
$this->tileSize = $tileSize;
27
$this->xRange = $xRange;
28
$this->yRange = $yRange;
30
// Determine desired image scale
31
$this->zoomOffset = $zoomLevel - $this->baseZoom;
32
$this->desiredScale = $this->baseScale * (pow(2, $this->zoomOffset));
37
* @return Returns an Imagick object representing the extracted region
39
protected function extractRegion($input, $output, $imageWidth, $imageHeight, $imageScale, $detector, $measurement) {
40
$cmd = "$this->kdu_expand -i " . $input . " -o $output ";
42
// Ratio of the desired scale to the actual JP2 image scale
43
$desiredToActual = $this->desiredScale / $imageScale;
46
$scaleFactor = log($desiredToActual, 2);
48
$relTs = $this->tileSize * $desiredToActual;
50
// Case 1: JP2 image resolution = desired resolution
51
// Nothing special to do...
53
// Case 2: JP2 image resolution > desired resolution (use -reduce)
54
if ($imageScale < $this->desiredScale) {
55
$cmd .= "-reduce " . $scaleFactor . " ";
58
// Case 3: JP2 image resolution < desired resolution (get smaller tile and then enlarge)
59
// Don't do anything yet...
61
// Check to see if the tile requested is within the range of available data
62
//$xRange = ceil($imageWidth / (2 * $desiredToActual * $this->tileSize));
63
//$yRange = ceil($imageHeight / (2 * $desiredToActual * $this->tileSize));
64
//if ((abs($x) > $xRange) || (abs($y) > $yRange)) {
65
// print "Out of range tile request... Range- x: $xRange, y: $yRange";
70
$cmd .= $this->getRegionString($imageWidth, $imageHeight, $relTs);
74
// Execute the command
76
exec('export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:' . "$this->kdu_lib_path; " . $cmd, $out, $ret);
79
throw new Exception("Failed to expand requested sub-region!<br><br> <b>Command:</b> '$cmd'");
81
} catch(Exception $e) {
82
echo '<span style="color:red;">Error:</span> ' .$e->getMessage();
86
$imcmd = "convert $output ";
88
// For images with transparent components, convert pixels with value "0" to be transparent.
89
if ($measurement == "0WL")
90
$imcmd .= "-transparent black ";
92
// Get dimensions of extracted region
93
$dimensions = split("x", trim(exec("identify $output | grep -o \" [0-9]*x[0-9]* \"")));
94
$tileWidth = $dimensions[0];
95
$tileHeight = $dimensions[1];
97
// Pad up the the relative tilesize (in cases where region extract for outer tiles is smaller than for inner tiles)
98
//$tileWidth = $im->getImageWidth();
99
//$tileHeight = $im->getImageHeight();
100
//if (($relTs < $this->tileSize) && (($tileWidth < $relTs) || ($tileHeight < $relTs))) {
101
// $this->padImage($im, $tileWidth, $tileHeight, $relTs, $this->xRange["start"], $this->yRange["start"]);
106
if (($detector == "EIT") || ($measurement == "0WL")) {
107
$clut = $this->getColorTable($detector, $measurement);
108
$imcmd .= "$clut -clut ";
111
// Pad if tile is smaller than it should be (Case 2)
112
if ($imageScale < $this->desiredScale) {
113
$imcmd .= $this->padImage($tif, $this->tileSize, $this->xRange["start"], $this->yRange["start"], $relTs);
116
// Resize if necessary (Case 3)
117
if ($relTs < $this->tileSize)
118
$imcmd .= "-geometry " . $this->tileSize . "x" . $this->tileSize . "! ";
119
//exec("convert -geometry " . $this->tileSize . "x" . $this->tileSize . "! $tif $tif", $out, $ret);
120
//$im->scaleImage($this->tileSize, $this->tileSize);
122
exec($imcmd . "$output");
124
//echo $imcmd . $tif;
132
* Build a region string to be used by kdu_expand. e.g. "-region {0.0,0.0},{0.5,0.5}"
134
public function getRegionString($jp2Width, $jp2Height, $ts) {
136
$top = $left = $width = $height = null;
138
// Number of tiles for the entire image
139
$imgNumTilesX = max(2, ceil($jp2Width / $ts));
140
$imgNumTilesY = max(2, ceil($jp2Height / $ts));
142
// Tile placement architecture expects an even number of tiles along each dimension
143
if ($imgNumTilesX % 2 != 0)
146
if ($imgNumTilesY % 2 != 0)
149
// Shift so that 0,0 now corresponds to the top-left tile
150
$relX = (0.5 * $imgNumTilesX) + $this->xRange["start"];
151
$relY = (0.5 * $imgNumTilesY) + $this->yRange["start"];
153
// number of tiles (may be greater than one for movies, etc)
154
$numTilesX = min($imgNumTilesX - $relX, $this->xRange["end"] - $this->xRange["start"] + 1);
155
$numTilesY = min($imgNumTilesY - $relY, $this->yRange["end"] - $this->yRange["start"] + 1);
157
// Number of "inner" tiles
158
$numTilesInsideX = $imgNumTilesX - 2;
159
$numTilesInsideY = $imgNumTilesY - 2;
161
// Dimensions for inner and outer tiles
163
$outerTS = ($jp2Width - ($numTilesInsideX * $innerTS)) / 2;
166
$top = (($relY == 0) ? 0 : $outerTS + ($relY - 1) * $innerTS) / $jp2Height;
169
$left = (($relX == 0) ? 0 : $outerTS + ($relX - 1) * $innerTS) / $jp2Width;
172
$height = ((($relY == 0) || ($relY == (imgNumTilesY -1))) ? $outerTS : $innerTS) / $jp2Height;
175
$width = ((($relX == 0) || ($relX == (imgNumTilesX -1))) ? $outerTS : $innerTS) / $jp2Width;
177
// {<top>,<left>},{<height>,<width>}
178
$region = "-region \{$top,$left\},\{$height,$width\}";
186
//function padImage($im, $ts, $x, $y) {
187
function padImage($tif, $ts, $x, $y, $relTs) {
188
$padx = $ts - $relTs;
189
$pady = $ts - $relTs;
192
if (($x == -1) && ($y == -1))
193
return "-background transparent -gravity SouthEast -extent $ts" . "x" . "$ts ";
196
if (($x == 0) && ($y == -1))
197
return "-background transparent -gravity SouthWest -extent $ts" . "x" . "$ts ";
200
if (($x == 0) && ($y == 0))
201
return "-background transparent -gravity NorthWest -extent $ts" . "x" . "$ts ";
204
if (($x == -1) && ($y == 0))
205
return "-background transparent -gravity NorthEast -extent $ts" . "x" . "$ts ";
209
private function padImage ($im, $jp2Width, $jp2Height, $tileWidth, $tileHeight, $ts, $x, $y) {
210
// Determine min and max tile numbers
211
$imgNumTilesX = max(2, ceil($jp2Width / $ts));
212
$imgNumTilesY = max(2, ceil($jp2Height / $ts));
213
$tileMinX = - ($imgNumTilesX / 2);
214
$tileMaxX = ($imgNumTilesX / 2) - 1;
215
$tileMinY = - ($imgNumTilesY / 2);
216
$tileMaxY = ($imgNumTilesY / 2) - 1;
218
// Determine where the tile is located (where tile should lie in the padding)
220
if ($x == $tileMinX) {
221
if ($y == $tileMinY) {
222
$gravity = "SouthEast";
224
else if ($y == $tileMaxY) {
225
$gravity = "NorthEast";
231
else if ($x == $tileMaxX) {
232
if ($y == $tileMinY) {
233
$gravity = "SouthWest";
235
else if ($y == $tileMaxY) {
236
$gravity = "NorthWest";
244
if ($y == $tileMinY) {
252
// Construct padding command
253
return "-background transparent -gravity $gravity -extent $ts" . "x" . "$ts ";
256
private function getColorTable($detector, $measurement) {
257
if ($detector == "EIT") {
258
return "/home/esahelio/public_html/images/color-tables/ctable_EIT_$measurement.png";
260
else if ($detector == "0C2") {
261
return "/home/esahelio/public_html/images/color-tables/ctable_idl_3.png";
263
else if ($detector == "0C3") {
264
return "/home/esahelio/public_html/images/color-tables/ctable_idl_1.png";
268
public function display() {
269
// Cache-Lifetime (in minutes)
271
$exp_gmt = gmdate("D, d M Y H:i:s", time() + $lifetime * 60) ." GMT";
272
header("Expires: " . $exp_gmt);
273
header("Cache-Control: public, max-age=" . $lifetime * 60);
275
// Special header for MSIE 5
276
header("Cache-Control: pre-check=" . $lifetime * 60, FALSE);
278
header( "Content-Type: image/png" );
280
readfile($this->image);