univ-pau-ics/build/service/CalendarExtractor.php

304 lines
7.0 KiB
PHP
Raw Normal View History

<?php
namespace service;
class CalendarExtractor{
/* [1] Attributes
=========================================================*/
private $start_d = null; // 1st day date
private $img_url = null; // image url
private $img_res = null; // image resource
private $event = []; // events
private $event_t = [ 0 ]; // types of 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
*
* @img_url<String> URL of the string to extract from
* @start_d<String> Date of the first day
*
* @return instance<CalendarExtractor> Instance
*
---------------------------------------------------------*/
public function __construct($img_url=null, $start_d=null){
/* [1] Check arguments
=========================================================*/ {
/* (1) Check type */
if( !is_string($img_url) || !is_string($start_d) )
throw new \Exception("CalendarExtractor.__construct(<String>, <String>) expected but CalendarExtractor.__construct(<".gettype($img_url).">, <".gettype($start_d).">) received");
/* (2) Check @img_url link availability */
if( !($img_head=@get_headers($img_url)) )
throw new \Exception("CalendarExtractor.__construct(<URL>, <String>) received but cannot reach <URL>");
if( !preg_match('@HTTP.+200@', $img_head[0]) )
throw new \Exception("CalendarExtractor.__construct(<URL>, <String>) received but cannot reach <URL>");
/* (3) Check @start_d format */
if( !preg_match("@^\d{1,2}-\d{1,2}-\d{3,}$@", $start_d) )
throw new \Exception("CalendarExtractor.__construct(<String>, <DATE>) received <DATE> has not the correct format");
}
/* [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;
$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]
];
}
}
/* [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
/* (3) Remove last */
unset( $col_ind[count($col_ind)-1] );
}
/* [3] For each day -> get events
=========================================================*/ {
/* (1) For each day */
foreach($col_ind as $day_n=>$col_x){
/* (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);
/* (4) If on black pixel and next not white */
if( $p == 0 && $p1 != 0xffffff ){
// {1} calculate time //
$time = $this->yToTime($day_n, $y);
// {2} Store new event type (if missing) //
if( !isset($this->event_t[$p1]) )
$this->event_t[$p1] = $this->event_t[0]++;
2017-09-12 15:53:49 +00:00
$uid = $this->event_t[$p1];
// {3} Store event start //
2017-09-12 15:53:49 +00:00
$this->event[$uid][$time] = [];
// {4} Seek end of event //
$y++;
while( $y < self::$stop_y && $this->getColor($col_x, $y) != 0 )
$y++;
// {5} If end reached //
2017-09-12 15:53:49 +00:00
$this->event[$uid][$time] = $this->yToTime($day_n, $y);
}
}
}
}
}
/* (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);
}
/* [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;
/* (5) Format to 2-digit */
$hour = ( $hour < 10 ) ? "0$hour" : $hour;
$min = ( $min < 10 ) ? "0$min" : $min ;
}
2017-09-12 20:15:51 +00:00
/* [3] Convert to GMT (UTC+0)
=========================================================*/
2017-09-12 20:30:30 +00:00
/* (1) Set fixed timezone offset */
$tz_offset = +2;
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);
}
/* (5) Generate ICS output
*
* @return ics<String> ICS Representation of the events
*
---------------------------------------------------------*/
public function toIcs(){
$RAW = "";
/* [1] Manage types
=========================================================*/
$type_name = [];
foreach($this->event_t as $color=>$uid)
$type_name[$uid] = $color;
/* [2] For each event
=========================================================*/
foreach($this->event as $event_t=>$events){
$type = "Event of type '".$type_name[$event_t]."'";
/* (2) For each event of each type
---------------------------------------------------------*/
foreach($events as $start_t=>$stop_t){
$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";
$RAW .= "DTEND:${stop_t}\n";
2017-09-12 21:08:13 +00:00
$RAW .= "UID:$start_t@xdrm.io\n"; // required
$RAW .= "SUMMARY:$type\n";
$RAW .= "END:VEVENT\n\n";
}
}
return $RAW;
}
}