2017-09-12 15:22:18 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace service;
|
|
|
|
|
2017-09-13 13:03:36 +00:00
|
|
|
use \lightdb\core\lightdb;
|
|
|
|
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
class CalendarExtractor{
|
|
|
|
|
|
|
|
|
|
|
|
/* [1] Attributes
|
|
|
|
=========================================================*/
|
|
|
|
private $start_d = null; // 1st day date
|
|
|
|
private $img_url = null; // image url
|
2017-09-13 13:03:36 +00:00
|
|
|
private $d_uid = null; // diplome uid
|
2017-09-12 15:22:18 +00:00
|
|
|
private $img_res = null; // image resource
|
|
|
|
private $event = []; // events
|
|
|
|
|
|
|
|
/* [2] Constants
|
|
|
|
=========================================================*/
|
|
|
|
public static $start_y = 79; // start y
|
|
|
|
public static $stop_y = 699; // stop y
|
|
|
|
public static $start_h = 8; // start hour
|
|
|
|
public static $stop_h = 20; // stop hour
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* (1) Builds a calendar extractor
|
|
|
|
*
|
2017-09-13 13:03:36 +00:00
|
|
|
* @d_uid<String> UID of the diplome
|
2017-09-12 15:22:18 +00:00
|
|
|
* @img_url<String> URL of the string to extract from
|
|
|
|
* @start_d<String> Date of the first day
|
|
|
|
*
|
|
|
|
* @return instance<CalendarExtractor> Instance
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
2017-09-13 13:03:36 +00:00
|
|
|
public function __construct($d_uid=null, $img_url=null, $start_d=null){
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
/* [1] Check arguments
|
|
|
|
=========================================================*/ {
|
|
|
|
|
|
|
|
/* (1) Check type */
|
|
|
|
if( !is_string($img_url) || !is_string($start_d) )
|
2017-09-13 13:03:36 +00:00
|
|
|
throw new \Exception("CalendarExtractor.__construct(<String>, <String>, <String>) expected but CalendarExtractor.__construct(<".gettype($d_uid).">, <".gettype($img_url).">, <".gettype($start_d).">) received");
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
/* (2) Check @img_url link availability */
|
|
|
|
if( !($img_head=@get_headers($img_url)) )
|
2017-09-13 13:03:36 +00:00
|
|
|
throw new \Exception("CalendarExtractor.__construct(<String>, <URL>, <String>) received but cannot reach <URL>");
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
if( !preg_match('@HTTP.+200@', $img_head[0]) )
|
2017-09-13 13:03:36 +00:00
|
|
|
throw new \Exception("CalendarExtractor.__construct(<String>, <URL>, <String>) received but cannot reach <URL>");
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
/* (3) Check @start_d format */
|
|
|
|
if( !preg_match("@^\d{1,2}-\d{1,2}-\d{3,}$@", $start_d) )
|
2017-09-13 13:03:36 +00:00
|
|
|
throw new \Exception("CalendarExtractor.__construct(<String>, <String>, <DATE>) received <DATE> has not the correct format");
|
|
|
|
|
|
|
|
/* (4) Check @d_uid format */
|
|
|
|
if( !preg_match("@^T\d+$@", $d_uid) )
|
|
|
|
throw new \Exception("CalendarExtractor.__construct(<UID>, <String>, <String>) received <UID> has not the correct format");
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* [2] Fetch file
|
|
|
|
=========================================================*/ {
|
|
|
|
|
|
|
|
/* (1) Try to open file with GD */
|
|
|
|
$this->img_res = @imagecreatefrompng($img_url);
|
|
|
|
|
|
|
|
/* (2) Manage error */
|
|
|
|
if( !$this->img_res )
|
|
|
|
throw new \Exception("URL is not a JPEG image, or is unreachable");
|
|
|
|
|
|
|
|
/* (3) Register data */
|
|
|
|
$this->img_url = $img_url;
|
2017-09-13 13:03:36 +00:00
|
|
|
$this->d_uid = $d_uid;
|
2017-09-12 15:22:18 +00:00
|
|
|
$this->start_d = $start_d;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* (2) Extracts calendar data from image
|
|
|
|
*
|
|
|
|
* @return error<bool> FALSE on error
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
public function process(){
|
|
|
|
|
|
|
|
/* [1] Global variables
|
|
|
|
=========================================================*/ {
|
|
|
|
|
|
|
|
/* (1) Image size */ {
|
|
|
|
|
|
|
|
// {1} Request for size //
|
|
|
|
$img_siz = @getimagesize($this->img_url);
|
|
|
|
|
|
|
|
// {2} If error //
|
|
|
|
if( !$img_siz )
|
|
|
|
throw new \Exception("Cannot get image size");
|
|
|
|
|
|
|
|
$img_siz = [
|
|
|
|
'w' => $img_siz[0],
|
|
|
|
'h' => $img_siz[1]
|
|
|
|
];
|
|
|
|
|
|
|
|
|
2017-09-13 13:03:36 +00:00
|
|
|
/* (2) Light database
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
|
|
|
|
/* (1) Create/Open database */
|
|
|
|
try{
|
|
|
|
$ldb = new lightdb('config');
|
|
|
|
|
|
|
|
/* (2) Manage error */
|
|
|
|
}catch(\Exception $e){
|
|
|
|
throw new \Exception("Cannot access database");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (3) Fetch diplome data */
|
|
|
|
$d_db = $ldb->fetch($this->d_uid);
|
|
|
|
|
|
|
|
/* (4) Manage error */
|
|
|
|
if( $d_db == false )
|
|
|
|
$d_db = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-09-12 15:22:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* [2] Extract day limits
|
|
|
|
=========================================================*/ {
|
|
|
|
|
|
|
|
/* (1) Will contain the column+1 w index */
|
|
|
|
$col_ind = [];
|
|
|
|
|
|
|
|
/* (2) Extract column indexes */
|
|
|
|
for( $x = 0 ; $x < $img_siz['w'] ; $x++ ){
|
|
|
|
|
|
|
|
if( $this->getColor($x, 62) <= 10 )
|
|
|
|
$col_ind[] = $x+1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-09-12 15:53:49 +00:00
|
|
|
|
2017-09-12 15:22:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* [3] For each day -> get events
|
|
|
|
=========================================================*/ {
|
|
|
|
|
2017-09-13 14:55:49 +00:00
|
|
|
$uid = 0;
|
|
|
|
|
2017-09-12 15:22:18 +00:00
|
|
|
/* (1) For each day */
|
2017-09-13 14:55:49 +00:00
|
|
|
for( $day_n = 0 ; $day_n < count($col_ind)-1 ; $day_n++ ){
|
2017-09-13 14:15:54 +00:00
|
|
|
$col_x = $col_ind[$day_n];
|
|
|
|
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
/* (2) For each y pixel -> exctract event */
|
|
|
|
for( $y = self::$start_y ; $y < self::$stop_y ; $y++ ){
|
|
|
|
|
|
|
|
/* (3) Get current color + next */
|
|
|
|
$p = $this->getColor($col_x, $y);
|
|
|
|
$p1 = $this->getColor($col_x, $y+1);
|
2017-09-13 13:03:36 +00:00
|
|
|
$p1e = '#'.dechex($p1);
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
/* (4) If on black pixel and next not white */
|
|
|
|
if( $p == 0 && $p1 != 0xffffff ){
|
|
|
|
|
|
|
|
// {1} calculate time //
|
2017-09-13 14:15:54 +00:00
|
|
|
$start_y = $y;
|
|
|
|
$time = $this->yToTime($day_n, $start_y);
|
2017-09-12 15:22:18 +00:00
|
|
|
|
2017-09-13 14:55:49 +00:00
|
|
|
// {2} Incr uid //
|
|
|
|
$uid++;
|
2017-09-12 15:53:49 +00:00
|
|
|
|
2017-09-12 15:22:18 +00:00
|
|
|
// {3} Store event start //
|
2017-09-13 14:55:49 +00:00
|
|
|
$this->event[$uid][$time] = [];
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
// {4} Seek end of event //
|
|
|
|
$y++;
|
|
|
|
while( $y < self::$stop_y && $this->getColor($col_x, $y) != 0 )
|
|
|
|
$y++;
|
|
|
|
|
2017-09-13 14:55:49 +00:00
|
|
|
|
2017-09-12 15:22:18 +00:00
|
|
|
// {5} If end reached //
|
2017-09-13 16:40:15 +00:00
|
|
|
$this->event[$uid][$time] = [ $this->yToTime($day_n, $y) ];
|
2017-09-12 15:22:18 +00:00
|
|
|
|
2017-09-13 14:15:54 +00:00
|
|
|
// {6} Exctract event's image //
|
2017-09-13 16:40:15 +00:00
|
|
|
$this->event[$uid][$time][1] = $this->extractEvent("$time-$uid", [$col_x, $start_y+1], [$col_ind[$day_n+1]-1, $y]);
|
2017-09-13 14:15:54 +00:00
|
|
|
|
|
|
|
|
2017-09-12 15:22:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-09-13 13:03:36 +00:00
|
|
|
|
|
|
|
/* [4] Save db changes
|
|
|
|
=========================================================*/
|
|
|
|
/* (1) Update data */
|
|
|
|
$ldb->delete($this->d_uid);
|
|
|
|
$ldb->insert($this->d_uid, $d_db);
|
|
|
|
|
|
|
|
/* (2) Close connection */
|
|
|
|
$ldb->close();
|
|
|
|
|
|
|
|
|
2017-09-12 15:22:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-09-13 15:24:07 +00:00
|
|
|
/* (3) Exctracts an event using OCR
|
2017-09-13 14:15:54 +00:00
|
|
|
*
|
2017-09-13 14:55:49 +00:00
|
|
|
* @uid<String> Image uid
|
2017-09-13 14:15:54 +00:00
|
|
|
* @start<Array> Start rect (x, y)
|
|
|
|
* @stop<Array> Stop rect (x, y)
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
2017-09-13 14:55:49 +00:00
|
|
|
public function extractEvent($uid, $start=null, $stop=null){
|
2017-09-13 15:24:07 +00:00
|
|
|
|
|
|
|
$link = __ROOT__."/tmp/$uid.jpeg";
|
2017-09-13 16:40:15 +00:00
|
|
|
$width = $stop[0]-$start[0];
|
|
|
|
$height = $stop[1]-$start[1];
|
2017-09-13 15:24:07 +00:00
|
|
|
|
2017-09-13 14:55:49 +00:00
|
|
|
/* [1] Get the right clip
|
2017-09-13 15:24:07 +00:00
|
|
|
=========================================================*/ {
|
|
|
|
/* (1) Create clipped copy */
|
2017-09-13 16:40:15 +00:00
|
|
|
$clip = \imagecreatetruecolor($width, $height);
|
2017-09-13 15:24:07 +00:00
|
|
|
|
|
|
|
$copied = \imagecopyresized(
|
|
|
|
$clip, // destin img
|
|
|
|
$this->img_res, // source img
|
|
|
|
0, // dest x
|
|
|
|
0, // dest y
|
|
|
|
$start[0], // src x
|
|
|
|
$start[1], // src y
|
2017-09-13 16:40:15 +00:00
|
|
|
$width, // dest w
|
|
|
|
$height, // dest h
|
|
|
|
$width, // src w
|
|
|
|
$height // src h
|
2017-09-13 15:24:07 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
/* (2) Manage copy error */
|
|
|
|
if( !$copied )
|
|
|
|
throw new \Exception("Cannot clip image");
|
|
|
|
|
2017-09-13 16:40:15 +00:00
|
|
|
/* (3) Save to base64 */
|
2017-09-13 15:24:07 +00:00
|
|
|
\imagesavealpha($clip, true);
|
|
|
|
|
2017-09-13 16:40:15 +00:00
|
|
|
ob_start();
|
|
|
|
\imagejpeg($clip);
|
|
|
|
$image_data = \base64_encode(ob_get_contents());
|
|
|
|
ob_end_clean();
|
2017-09-13 15:24:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
}
|
2017-09-13 14:55:49 +00:00
|
|
|
|
2017-09-13 16:40:15 +00:00
|
|
|
|
|
|
|
return $image_data;
|
2017-09-13 14:15:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-12 15:22:18 +00:00
|
|
|
/* (3) Get a pixel's color
|
|
|
|
*
|
|
|
|
* @x<int> X coordinate
|
|
|
|
* @y<int> Y coordinate
|
|
|
|
*
|
|
|
|
* @return color<u_int32> Raw color
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
private function getColor($x, $y){
|
|
|
|
return imagecolorat($this->img_res, $x, $y);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* (4) Get time from a y-coordinate
|
|
|
|
*
|
|
|
|
* @day_n<int> Day relative index
|
|
|
|
* @y<int> y Coordinate
|
|
|
|
*
|
|
|
|
* @return time<String> Formatted time (HH:mm)
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
private function yToTime($day_n, $y){
|
|
|
|
|
|
|
|
/* [1] Get the date
|
|
|
|
=========================================================*/ {
|
|
|
|
|
|
|
|
/* (1) Get the day's date */
|
|
|
|
$day_ts = strtotime($this->start_d." + $day_n days");
|
|
|
|
|
|
|
|
/* (2) Format it */
|
2017-09-12 15:53:49 +00:00
|
|
|
$day = date('Ymd', $day_ts);
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* [2] Get the time
|
|
|
|
=========================================================*/{
|
|
|
|
|
|
|
|
/* (1) Get the time */
|
|
|
|
$time = self::$start_h + (self::$stop_h-self::$start_h) * ($y-self::$start_y) / (self::$stop_y-self::$start_y);
|
|
|
|
|
|
|
|
/* (2) Calculate hour form time */
|
|
|
|
$hour = floor($time);
|
|
|
|
|
|
|
|
/* (3) Calculate min from time */
|
|
|
|
$min = round( 60 * ($time-$hour) );
|
|
|
|
|
|
|
|
/* (4) Round minutes to 10min */
|
2017-09-12 15:53:49 +00:00
|
|
|
$min = round($min/10)*10;
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
/* (5) Format to 2-digit */
|
|
|
|
$hour = ( $hour < 10 ) ? "0$hour" : $hour;
|
|
|
|
$min = ( $min < 10 ) ? "0$min" : $min ;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-09-12 19:57:08 +00:00
|
|
|
|
2017-09-12 20:15:51 +00:00
|
|
|
/* [3] Convert to GMT (UTC+0)
|
2017-09-12 19:57:08 +00:00
|
|
|
=========================================================*/
|
2017-09-12 20:30:30 +00:00
|
|
|
/* (1) Set fixed timezone offset */
|
|
|
|
$tz_offset = +2;
|
2017-09-12 19:57:08 +00:00
|
|
|
|
2017-09-12 20:30:30 +00:00
|
|
|
/* (2) Get GMT (UTC+0) timestamp */
|
2017-09-12 21:18:13 +00:00
|
|
|
$ts = strtotime("${day} $hour:$min:00") - (3600*$tz_offset);
|
2017-09-12 20:30:30 +00:00
|
|
|
|
|
|
|
/* (3) Return GMT date */
|
2017-09-12 21:18:13 +00:00
|
|
|
return date("Ymd\THis\Z", $ts);
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* (5) Generate ICS output
|
|
|
|
*
|
|
|
|
* @return ics<String> ICS Representation of the events
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
2017-09-12 16:09:51 +00:00
|
|
|
public function toIcs(){
|
|
|
|
$RAW = "";
|
|
|
|
|
2017-09-13 13:03:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* [1] Get light-database
|
2017-09-12 16:09:51 +00:00
|
|
|
=========================================================*/
|
2017-09-13 13:03:36 +00:00
|
|
|
/* (1) Create/Open database */
|
|
|
|
try{
|
|
|
|
$ldb = new lightdb('config');
|
|
|
|
|
|
|
|
/* (2) Manage error */
|
|
|
|
}catch(\Exception $e){
|
|
|
|
throw new \Exception("Cannot access database");
|
|
|
|
}
|
2017-09-12 16:09:51 +00:00
|
|
|
|
2017-09-13 13:03:36 +00:00
|
|
|
/* (3) Get color association if available */
|
|
|
|
$col_assoc = [];
|
|
|
|
if( !is_null($ldb->index($this->d_uid)) )
|
|
|
|
$col_assoc = $ldb->fetch($this->d_uid);
|
2017-09-12 16:09:51 +00:00
|
|
|
|
2017-09-13 13:03:36 +00:00
|
|
|
// var_dump($col_assoc);
|
|
|
|
// die(1);
|
2017-09-12 16:09:51 +00:00
|
|
|
|
|
|
|
/* [2] For each event
|
|
|
|
=========================================================*/
|
2017-09-13 13:03:36 +00:00
|
|
|
foreach($this->event as $event_col=>$events){
|
2017-09-12 16:09:51 +00:00
|
|
|
|
2017-09-13 14:55:49 +00:00
|
|
|
$type = "unknown";
|
|
|
|
|
|
|
|
if( isset($col_assoc[$event_col]) )
|
|
|
|
$type = $col_assoc[$event_col];
|
2017-09-12 16:09:51 +00:00
|
|
|
|
|
|
|
/* (2) For each event of each type
|
|
|
|
---------------------------------------------------------*/
|
2017-09-13 16:40:15 +00:00
|
|
|
foreach($events as $start_t=>$data){
|
2017-09-12 16:09:51 +00:00
|
|
|
$RAW .= "BEGIN:VEVENT\n";
|
2017-09-12 21:12:21 +00:00
|
|
|
$RAW .= "DTSTAMP:".gmdate("Ymd\THis\Z", time())."\n"; // required
|
|
|
|
$RAW .= "DTSTART:${start_t}\n";
|
2017-09-13 16:40:15 +00:00
|
|
|
$RAW .= "DTEND:${data[0]}\n";
|
2017-09-12 21:28:10 +00:00
|
|
|
$RAW .= "UID:$start_t-univ-pau-ics\n"; // required
|
2017-09-12 16:09:51 +00:00
|
|
|
$RAW .= "SUMMARY:$type\n";
|
2017-09-13 16:40:15 +00:00
|
|
|
$RAW .= "ATTACH;ENCODING=BASE64;VALUE=BINARY;FILENAME=att.jpg:${data[1]}\n";
|
2017-09-12 21:28:10 +00:00
|
|
|
$RAW .= "CATEGORIES: UPPA Calendar\n";
|
|
|
|
$RAW .= "END:VEVENT\n";
|
2017-09-12 16:09:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return $RAW;
|
|
|
|
|
|
|
|
}
|
2017-09-12 15:22:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
}
|