2010-02-23 17:12:12 +08:00
< ? php
//
// ZoneMinder web image view file, $Date: 2008-09-29 14:15:13 +0100 (Mon, 29 Sep 2008) $, $Revision: 2640 $
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
2016-12-26 23:23:16 +08:00
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2010-02-23 17:12:12 +08:00
//
2015-08-10 00:02:13 +08:00
// Calling sequence: ... /zm/index.php?view=image&path=/monid/path/image.jpg&scale=nnn&width=wwww&height=hhhhh
//
// Path is physical path to the image starting at the monitor id
//
// Scale is optional and between 1 and 400 (percent),
// Omitted or 100 = no scaling done, image passed through directly
// Scaling will increase response time slightly
//
2015-08-10 06:19:12 +08:00
// width and height are each optional, ideally supply both, but if only one is supplied the other is calculated
// These are in pixels
2015-08-10 00:02:13 +08:00
//
2015-08-10 06:19:12 +08:00
// If both scale and either width or height are specified, scale is ignored
2015-08-10 00:02:13 +08:00
//
2016-05-17 00:23:19 +08:00
if ( ! canView ( 'Events' ) ) {
2017-05-19 00:49:59 +08:00
$view = 'error' ;
return ;
2010-02-23 17:12:12 +08:00
}
2016-01-15 02:35:30 +08:00
require_once ( 'includes/Event.php' );
2016-04-26 02:59:55 +08:00
require_once ( 'includes/Frame.php' );
2016-01-15 02:35:30 +08:00
2015-11-16 05:40:25 +08:00
// Compatibility for PHP 5.4
2016-05-17 00:23:19 +08:00
if ( ! function_exists ( 'imagescale' )) {
function imagescale ( $image , $new_width , $new_height = - 1 , $mode = 0 ) {
$mode ; // Not supported
2015-11-16 05:40:25 +08:00
2016-05-17 00:23:19 +08:00
$new_height = ( $new_height == - 1 ) ? imagesy ( $image ) : $new_height ;
$imageNew = imagecreatetruecolor ( $new_width , $new_height );
imagecopyresampled ( $imageNew , $image , 0 , 0 , 0 , 0 , ( int ) $new_width , ( int ) $new_height , imagesx ( $image ), imagesy ( $image ));
2016-05-03 01:36:19 +08:00
2016-05-17 00:23:19 +08:00
return $imageNew ;
}
2015-11-16 05:40:25 +08:00
}
2010-02-23 17:12:12 +08:00
$errorText = false ;
2016-11-22 01:28:15 +08:00
$filename = '' ;
2017-01-14 03:42:10 +08:00
$Frame = null ;
$Event = null ;
2017-04-08 01:20:54 +08:00
$path = null ;
2016-11-22 01:28:15 +08:00
2016-05-17 00:23:19 +08:00
if ( empty ( $_REQUEST [ 'path' ]) ) {
2017-10-11 03:11:59 +08:00
2017-11-02 21:00:01 +08:00
if ( ! empty ( $_REQUEST [ 'fid' ]) ) {
if ( $_REQUEST [ 'fid' ] == 'snapshot' ) {
$Event = new Event ( $_REQUEST [ 'eid' ] );
2017-10-11 03:11:59 +08:00
$Frame = new Frame ();
$Frame -> FrameId ( 'snapshot' );
2017-11-02 21:00:01 +08:00
$path = $Event -> Path () . '/snapshot.jpg' ;
} else {
2017-10-11 03:11:59 +08:00
2017-11-02 21:00:01 +08:00
$show = empty ( $_REQUEST [ 'show' ]) ? 'capture' : $_REQUEST [ 'show' ];
2017-10-11 03:11:59 +08:00
2017-11-02 21:00:01 +08:00
if ( ! empty ( $_REQUEST [ 'eid' ] ) ) {
2018-04-21 02:25:54 +08:00
$Event = Event :: find_one ( array ( 'Id' => $_REQUEST [ 'eid' ]));
if ( ! $Event ) {
header ( 'HTTP/1.0 404 Not Found' );
Fatal ( 'Event ' . $_REQUEST [ 'eid' ] . ' Not found' );
return ;
}
$Frame = Frame :: find_one ( array ( 'EventId' => $_REQUEST [ 'eid' ], 'FrameId' => $_REQUEST [ 'fid' ]));
2017-11-02 21:00:01 +08:00
if ( ! $Frame ) {
2018-04-21 02:25:54 +08:00
$previousBulkFrame = dbFetchOne ( 'SELECT * FROM Frames WHERE EventId=? AND FrameId < ? ORDER BY FrameID DESC LIMIT 1' , NULL , array ( $_REQUEST [ 'eid' ], $_REQUEST [ 'fid' ] ) );
2017-11-02 21:04:58 +08:00
$nextBulkFrame = dbFetchOne ( " SELECT * FROM Frames WHERE EventId=? AND FrameId > ? ORDER BY FrameID ASC LIMIT 1 " , NULL , array ( $_REQUEST [ 'eid' ], $_REQUEST [ 'fid' ] ) );
2017-10-17 03:16:19 +08:00
if ( $previousBulkFrame and $nextBulkFrame ) {
$Frame = new Frame ( $previousBulkFrame );
2017-10-18 01:09:30 +08:00
$Frame -> FrameId ( $_REQUEST [ 'fid' ] );
2017-10-18 02:53:34 +08:00
2017-11-17 01:48:04 +08:00
$percentage = ( $Frame -> FrameId () - $previousBulkFrame [ 'FrameId' ]) / ( $nextBulkFrame [ 'FrameId' ] - $previousBulkFrame [ 'FrameId' ]);
2017-10-18 02:53:34 +08:00
$Frame -> Delta ( $previousBulkFrame [ 'Delta' ] + floor ( 100 * ( $nextBulkFrame [ 'Delta' ] - $previousBulkFrame [ 'Delta' ] ) * $percentage ) / 100 );
Logger :: Debug ( " Got virtual frame from Bulk Frames previous delta: " . $previousBulkFrame [ 'Delta' ] . " + nextdelta: " . $nextBulkFrame [ 'Delta' ] . ' - ' . $previousBulkFrame [ 'Delta' ] . ' * ' . $percentage );
2017-10-17 03:16:19 +08:00
} else {
2017-10-11 03:11:59 +08:00
Fatal ( " No Frame found for event( " . $_REQUEST [ 'eid' ] . " ) and frame id( " . $_REQUEST [ 'fid' ] . " ) " );
2017-10-17 03:16:19 +08:00
}
2017-10-11 03:11:59 +08:00
}
2017-10-17 03:16:19 +08:00
// Frame can be non-existent. We have Bulk frames. So now we should try to load the bulk frame
2017-10-11 03:11:59 +08:00
} else {
2016-05-03 01:36:19 +08:00
# If we are only specifying fid, then the fid must be the primary key into the frames table. But when the event is specified, then it is the frame #
2018-04-21 02:25:54 +08:00
$Frame = Frame :: find_one ( array ( 'Id' => $_REQUEST [ 'fid' ]));
if ( ! $Frame ) {
header ( 'HTTP/1.0 404 Not Found' );
Fatal ( 'Frame ' . $_REQUEST [ 'fid' ] . ' Not Found' );
return ;
}
$Event = Event :: find_one ( array ( 'Id' => $Frame -> EventId ()));
if ( ! $Event ) {
header ( 'HTTP/1.0 404 Not Found' );
Fatal ( 'Event ' . $Frame -> EventId () . ' Not Found' );
return ;
}
2017-10-11 03:11:59 +08:00
}
$path = $Event -> Path () . '/' . sprintf ( '%0' . ZM_EVENT_IMAGE_DIGITS . 'd' , $Frame -> FrameId ()) . '-' . $show . '.jpg' ;
2016-05-12 23:55:48 +08:00
}
2016-11-22 01:28:15 +08:00
2016-05-12 23:55:48 +08:00
} else {
2018-04-21 02:25:54 +08:00
header ( 'HTTP/1.0 404 Not Found' );
Fatal ( 'No Frame ID specified' );
2017-04-08 01:20:54 +08:00
return ;
2016-05-12 23:55:48 +08:00
}
2016-05-06 02:49:40 +08:00
if ( ! file_exists ( $path ) ) {
2017-05-19 00:49:59 +08:00
Logger :: Debug ( " $path does not exist " );
2016-05-06 02:49:40 +08:00
# Generate the frame JPG
2016-10-21 00:01:25 +08:00
if ( $show == 'capture' and $Event -> DefaultVideo () ) {
2018-03-29 04:01:58 +08:00
if ( ! file_exists ( $Event -> Path () . '/' . $Event -> DefaultVideo ()) ) {
header ( 'HTTP/1.0 404 Not Found' );
Fatal ( " Can't create frame images from video becuase there is no video file for this event at ( " . $Event -> Path () . '/' . $Event -> DefaultVideo () );
}
2017-04-13 04:17:19 +08:00
$command = 'ffmpeg -ss ' . $Frame -> Delta () . ' -i ' . $Event -> Path () . '/' . $Event -> DefaultVideo () . ' -frames:v 1 ' . $path ;
#$command ='ffmpeg -ss '. $Frame->Delta() .' -i '.$Event->Path().'/'.$Event->DefaultVideo().' -vf "select=gte(n\\,'.$Frame->FrameId().'),setpts=PTS-STARTPTS" '.$path;
2016-05-17 00:23:19 +08:00
#$command ='ffmpeg -v 0 -i '.$Storage->Path().'/'.$Event->Path().'/'.$Event->DefaultVideo().' -vf "select=gte(n\\,'.$Frame->FrameId().'),setpts=PTS-STARTPTS" '.$path;
2017-05-19 00:49:59 +08:00
Logger :: Debug ( " Running $command " );
2016-05-17 00:23:19 +08:00
$output = array ();
$retval = 0 ;
exec ( $command , $output , $retval );
2017-05-19 02:43:17 +08:00
Logger :: Debug ( " Command: $command , retval: $retval , output: " . implode ( " \n " , $output ));
2016-09-21 03:55:28 +08:00
if ( ! file_exists ( $path ) ) {
2017-05-19 00:49:59 +08:00
header ( 'HTTP/1.0 404 Not Found' );
2016-09-21 03:55:28 +08:00
Fatal ( " Can't create frame images from video for this event ( " . $Event -> DefaultVideo () );
}
2017-10-24 01:55:24 +08:00
$Event -> DiskSpace ( null );
2017-10-24 08:04:02 +08:00
$Event -> save ();
2016-05-17 00:23:19 +08:00
} else {
2017-05-19 00:49:59 +08:00
header ( 'HTTP/1.0 404 Not Found' );
2016-05-17 00:23:19 +08:00
Fatal ( " Can't create frame images from video becuase there is no video file for this event ( " . $Event -> DefaultVideo () );
2010-02-23 17:12:12 +08:00
}
2016-05-06 02:49:40 +08:00
}
2016-05-17 00:23:19 +08:00
} else {
2017-05-19 00:49:59 +08:00
Warning ( 'Loading images by path is deprecated' );
2017-01-26 06:14:30 +08:00
$dir_events = realpath ( ZM_DIR_EVENTS );
$path = realpath ( $dir_events . '/' . $_REQUEST [ 'path' ]);
$pos = strpos ( $path , $dir_events );
2017-01-25 23:05:34 +08:00
2017-05-19 00:49:59 +08:00
if ( $pos == 0 && $pos !== false ) {
if ( ! empty ( $user [ 'MonitorIds' ] ) ) {
2017-01-26 06:14:30 +08:00
$imageOk = false ;
2017-05-19 00:49:59 +08:00
$pathMonId = substr ( $path , 0 , strspn ( $path , '1234567890' ) );
2017-01-26 06:14:30 +08:00
foreach ( preg_split ( '/["\'\s]*,["\'\s]*/' , $user [ 'MonitorIds' ] ) as $monId ) {
if ( $pathMonId == $monId ) {
$imageOk = true ;
break ;
2010-02-23 17:12:12 +08:00
}
2016-05-17 00:23:19 +08:00
}
2017-01-26 06:14:30 +08:00
if ( ! $imageOk )
2017-05-19 00:49:59 +08:00
$errorText = 'No image permissions' ;
2010-02-23 17:12:12 +08:00
}
2017-01-26 06:14:30 +08:00
} else {
2017-05-19 00:49:59 +08:00
$errorText = 'Invalid image path' ;
2016-05-17 00:23:19 +08:00
}
if ( ! file_exists ( $path ) ) {
2016-10-21 00:01:25 +08:00
header ( 'HTTP/1.0 404 Not Found' );
2016-05-17 00:23:19 +08:00
Fatal ( " Image not found at $path " );
}
2010-02-23 17:12:12 +08:00
}
2015-08-10 06:41:12 +08:00
$scale = 0 ;
2016-05-17 00:23:19 +08:00
if ( ! empty ( $_REQUEST [ 'scale' ]) ) {
if ( is_numeric ( $_REQUEST [ 'scale' ])) {
$x = $_REQUEST [ 'scale' ];
if ( $x >= 1 and $x <= 400 )
$scale = $x ;
}
2016-05-03 01:36:19 +08:00
}
2010-02-23 17:12:12 +08:00
2015-08-10 00:02:13 +08:00
$width = 0 ;
2016-05-17 00:23:19 +08:00
if ( ! empty ( $_REQUEST [ 'width' ]) ) {
if ( is_numeric ( $_REQUEST [ 'width' ])) {
$x = $_REQUEST [ 'width' ];
if ( $x >= 10 and $x <= 8000 )
$width = $x ;
}
2016-05-03 01:36:19 +08:00
}
2015-08-10 00:02:13 +08:00
$height = 0 ;
2016-05-17 00:23:19 +08:00
if ( ! empty ( $_REQUEST [ 'height' ]) ) {
if ( is_numeric ( $_REQUEST [ 'height' ])) {
$x = $_REQUEST [ 'height' ];
if ( $x >= 10 and $x <= 8000 )
$height = $x ;
}
2016-05-03 01:36:19 +08:00
}
2015-08-10 00:02:13 +08:00
2016-09-21 03:55:28 +08:00
header ( 'Content-type: image/jpeg' );
2016-11-22 01:28:15 +08:00
# This is so that Save Image As give a useful filename
2017-01-14 03:42:10 +08:00
if ( $Event ) {
2017-01-26 06:14:30 +08:00
$filename = $Event -> MonitorId () . '_' . $Event -> Id () . '_' . $Frame -> FrameId () . '.jpg' ;
header ( 'Content-Disposition: inline; filename="' . $filename . '"' );
2017-01-14 03:42:10 +08:00
}
2016-09-22 22:37:32 +08:00
ob_clean ();
flush ();
2016-09-21 03:55:28 +08:00
2016-05-03 01:36:19 +08:00
if ( $errorText ) {
2016-05-17 00:23:19 +08:00
Error ( $errorText );
2016-05-03 01:36:19 +08:00
} else {
2016-05-17 00:23:19 +08:00
if ( ( $scale == 0 || $scale == 100 ) && $width == 0 && $height == 0 ) {
if ( ! readfile ( $path ) ) {
Error ( " No bytes read from " . $path );
2010-02-23 17:12:12 +08:00
}
2016-05-03 01:36:19 +08:00
} else {
2017-05-19 00:49:59 +08:00
Logger :: Debug ( " Doing a scaled image: scale( $scale ) width( $width ) height( $height ) " );
2016-05-17 00:23:19 +08:00
$i = 0 ;
if ( ! ( $width && $height ) ) {
$i = imagecreatefromjpeg ( $path );
$oldWidth = imagesx ( $i );
$oldHeight = imagesy ( $i );
if ( $width == 0 && $height == 0 ) { // scale has to be set to get here with both zero
$width = $oldWidth * $scale / 100.0 ;
$height = $oldHeight * $scale / 100.0 ;
} elseif ( $width == 0 && $height != 0 ) {
$width = ( $height * $oldWidth ) / $oldHeight ;
} elseif ( $width != 0 && $height == 0 ) {
$height = ( $width * $oldHeight ) / $oldWidth ;
}
if ( $width == $oldWidth && $height == $oldHeight ) {
2016-10-21 00:01:25 +08:00
Warning ( 'No change to width despite scaling.' );
2016-05-17 00:23:19 +08:00
}
}
# Slight optimisation, thumbnails always specify width and height, so we can cache them.
$scaled_path = preg_replace ( '/\.jpg$/' , " - ${ width}x${height } .jpg " , $path );
2016-09-21 03:55:28 +08:00
if ( ! file_exists ( $scaled_path ) or ! readfile ( $scaled_path ) ) {
2017-05-19 00:49:59 +08:00
Logger :: Debug ( " Cached scaled image does not exist at $scaled_path or is no good.. Creating it " );
2016-05-17 00:23:19 +08:00
ob_start ();
if ( ! $i )
$i = imagecreatefromjpeg ( $path );
$iScale = imagescale ( $i , $width , $height );
imagejpeg ( $iScale );
imagedestroy ( $i );
imagedestroy ( $iScale );
$scaled_jpeg_data = ob_get_contents ();
file_put_contents ( $scaled_path , $scaled_jpeg_data );
ob_end_clean ();
echo $scaled_jpeg_data ;
}
}
2016-05-03 01:36:19 +08:00
}