2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
* Helioviewer Tile Class Definition
10
* @author Keith Hughitt <keith.hughitt@nasa.gov>
11
* @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
12
* @link http://launchpad.net/helioviewer.org
15
* To improve smoothness of transparency edges, use a larger mask (e.g.
16
* 2080x2080 instead of 1040x1040) so that most of scaling will be downwards
18
require_once 'Tile.php';
20
class HelioviewerTile extends Tile
22
private $_observatory;
25
private $_measurement;
26
private $_cacheDir = HV_CACHE_DIR;
27
private $_noImage = HV_EMPTY_TILE;
30
* Helioviewer Tile Constructor
32
* @param string $uri URI for the original JPEG 2000 image
33
* @param int $x Helioviewer.org tile x-coordinate
34
* @param int $y Helioviewer.org tile y-coordinate
35
* @param int $zoom Helioviewer.org zoom-level
36
* @param int $tileSize Requested tile size (width and height)
37
* @param int $jp2Width Width of the original JP2 image
38
* @param int $jp2Height Height of the original JP2 image
39
* @param float $jp2Scale Plate scale (arc-seconds/pixal) of original image
40
* @param float $offsetX Amount original image is offset from sun center (x)
41
* @param float $offsetY Amount original image is offset from sun center (y)
42
* @param string $format Desired format for resulting tile image
43
* @param string $obs Observatory
44
* @param string $inst Instrument
45
* @param string $det Detector
46
* @param string $meas Measurement
47
* @param bool $display Display the tile immediately or generate only
51
public function __construct(
52
$uri, $x, $y, $zoom, $tileSize, $jp2Width, $jp2Height, $jp2Scale,
53
$offsetX, $offsetY, $format, $obs, $inst, $det, $meas, $display = true
55
$this->_observatory = $obs;
56
$this->_instrument = $inst;
57
$this->_detector = $det;
58
$this->_measurement = $meas;
59
$this->zoomLevel = $zoom;
60
$this->offsetX = $offsetX;
61
$this->offsetY = $offsetY;
63
$jp2 = HV_JP2_DIR . $uri;
64
$tile = $this->_getTileFilepath($jp2, $x, $y, $format);
66
// If tile already exists in cache, use it
67
// TODO: Once a smarter caching system is in place, take advantage of
68
// which data we know will be cached (e.g. most recent 2 weeks), and
69
// skip file_exists check.
70
if (!HV_DISABLE_CACHE && $display) {
71
if (file_exists($tile)) {
72
$this->displayCachedTile($tile);
76
$desiredScale = $this->_getImageScale($zoom);
78
// Now we are ready to call the base Tile constructor
80
$jp2, $tile, $x, $y, $desiredScale, $tileSize, $jp2Width, $jp2Height, $jp2Scale, $format
83
$colorTable = $this->_getColorTable();
86
$this->setColorTable($colorTable);
89
if ($this->_instrument == "LASCO") {
90
$this->setAlphaMask(true);
103
* @param string $jp2 The location of the tile's source JP2 image.
104
* @param int $x Tile x-coordinate
105
* @param int $y Tile y-coordinate
106
* @param string $format The file format used by the tile
108
* @return string The path in the cache where the tile should be stored
110
private function _getTileFilepath($jp2, $x, $y, $format)
113
$filepath = $this->_cacheDir . "/";
116
$exploded = explode("/", $jp2);
117
$filename = substr(end($exploded), 0, -4);
120
$year = substr($filename, 0, 4);
121
$month = substr($filename, 5, 2);
122
$day = substr($filename, 8, 2);
125
$year, $month, $day, $this->_observatory, $this->_instrument,
126
$this->_detector, $this->_measurement
129
foreach ($fieldArray as $field) {
130
$filepath .= str_replace(" ", "_", $field) . "/";
133
// Convert coordinates to strings
134
$xStr = "+" . str_pad($x, 2, '0', STR_PAD_LEFT);
135
if (substr($x, 0, 1) == "-") {
136
$xStr = "-" . str_pad(substr($x, 1), 2, '0', STR_PAD_LEFT);
139
$yStr = "+" . str_pad($y, 2, '0', STR_PAD_LEFT);
140
if (substr($y, 0, 1) == "-") {
141
$yStr = "-" . str_pad(substr($y, 1), 2, '0', STR_PAD_LEFT);
144
$filepath .= $filename . "_" . $this->zoomLevel . "_" . $xStr . "_" . $yStr . ".$format";
150
* Translates a given zoom-level into an image plate scale.
152
* @param int $zoomLevel Zoom-level for given tile request
154
* @return float Returns the arc-seconds/pixal equivalent of the requested zoom-level.
156
private function _getImageScale($zoomLevel)
158
$zoomOffset = $zoomLevel - HV_BASE_ZOOM_LEVEL;
159
return HV_BASE_IMAGE_SCALE * (pow(2, $zoomOffset));
163
* Gets the filepath for the color look-up table that corresponds to the image.
165
* Note 2009/09/15: Would it make sense to return color table when initially
166
* looking up image, and pass to tile requests?
168
* @return string|bool Returns the filepath for the color lookup table, or false
171
private function _getColorTable()
173
//$rootdir = substr(getcwd(), 0, -4);
175
if ($this->_detector == "EIT") {
176
return HV_ROOT_DIR . "/images/color-tables/ctable_EIT_" . $this->_measurement . ".png";
177
} else if ($this->_detector == "C2") {
178
return HV_ROOT_DIR . "/images/color-tables/ctable_idl_3.png";
179
} else if ($this->_detector == "C3") {
180
return HV_ROOT_DIR . "/images/color-tables/ctable_idl_1.png";
187
* Generates a portion of an ImageMagick convert command to apply an alpha mask
188
* Note: Values for radii used to generate the LASCO C2 & C3 alpha masks:
189
* rocc_outer = 7.7; // (.9625 * orig)
190
* rocc_inner = 2.415; // (1.05 * orig)
192
* Generating the alpha masks:
193
* $rsun = 80.814221; // solar radius in image pixels
194
* $rocc_inner = 2.415;
197
* // convert to pixels
198
* $radius_inner = $rocc_inner * $rsun;
199
* $radius_outer = $rocc_outer * $rsun;
200
* $innerCircleY = $crpix2 + $radius_inner;
201
* $outerCircleY = $crpix2 + $radius_outer;
203
* exec("convert -size 1024x1024 xc:black -fill white -draw \"circle $crpix1,$crpix2 $crpix1,$outerCircleY\"
204
* -fill black -draw \"circle $crpix1,$crpix2 $crpix1,$innerCircleY\" +antialias LASCO_C2_Mask.png")
206
* @param string $input image filepath
208
* @return string An imagemagick sub-command for generating the necessary alpha mask
210
public function applyAlphaMask($input)
215
if ($this->_detector == "C2") {
216
$mask = HV_ROOT_DIR . "/images/alpha-masks/LASCO_C2_Mask.png";
217
} else if ($this->_detector == "C3") {
218
$mask = HV_ROOT_DIR . "/images/alpha-masks/LASCO_C3_Mask.png";
221
// Ratio of the original image scale to the desired scale
222
$actualToDesired = 1 / $this->desiredToActual;
225
$offsetX = $this->offsetX + (($maskWidth - $this->jp2Width + $this->roi["left"]) * $actualToDesired);
226
$offsetY = $this->offsetY + (($maskHeight - $this->jp2Height + $this->roi["top"]) * $actualToDesired);
229
$cmd = sprintf(" %s -scale %s %s -alpha Off -compose copy_opacity -composite ", $input, $scale, $mask);
230
$str = " -geometry %s%s %s \( -resize '%s%%' %s \) -alpha Off -compose copy_opacity -composite ";
231
$cmd = sprintf($str, $offsetX, $offsetY, $input, 100 * $actualToDesired, $mask);
232
$str = " %s -extent 512x512 \( -resize '%f%%' -crop %fx%f%+f%+f %s \) -compose copy_opacity " .
233
"-composite -channel A -threshold 50%% ";
235
$str = " -respect-parenthesis \( %s -gravity SouthWest -background black -extent 512x512 \) " .
236
"\( %s -resize '%f%%' -crop %fx%f%+f%+f +repage -monochrome -gravity SouthWest " .
237
"-background black -extent 512x512 \) -alpha off -compose copy_opacity -composite ";
239
$str, $input, $mask, 100 * $actualToDesired,
240
$this->subfieldRelWidth, $this->subfieldRelHeight, $offsetX, $offsetY
247
* Displays the image on the page
249
* @param string $tile Filepath to the cached tile.
251
* @TODO: Would it be better to make SubFieldImage->display static and call? Or instantiate
252
* super classes (Tile and SubFieldImage), and then call display normally?
256
public function displayCachedTile($tile)
259
$format = substr($tile, -3);
261
// Cache-Lifetime (in minutes)
263
$exp_gmt = gmdate("D, d M Y H:i:s", time() + $lifetime * 60) ." GMT";
264
header("Expires: " . $exp_gmt);
265
header("Cache-Control: public, max-age=" . $lifetime * 60);
267
// Filename & Content-length
268
$exploded = explode("/", $tile);
269
$filename = end($exploded);
272
header("Content-Length: " . $stat['size']);
273
header("Content-Disposition: inline; filename=\"$filename\"");
275
if ($format == "png") {
276
header("Content-Type: image/png");
278
header("Content-Type: image/jpeg");
281
if (!readfile($tile)) {
282
throw new Exception("Error displaying $filename\n");
284
} catch (Exception $e) {
285
header("Content-Type: text/html");
286
$msg = "[PHP][" . date("Y/m/d H:i:s") . "]\n\t " . $e->getMessage() . "\n\n";
287
file_put_contents(HV_ERROR_LOG, $msg, FILE_APPEND);
295
//private function hasAlphaMask() {
296
// return $this->_measurement === "0WL" ? true : false;
b'\\ No newline at end of file'