UID of the diplome * @img_url URL of the string to extract from * @start_d Date of the first day * * @return instance Instance * ---------------------------------------------------------*/ public function __construct($d_uid=null, $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(, , ) expected but CalendarExtractor.__construct(<".gettype($d_uid).">, <".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(, , ) received but cannot reach "); if( !preg_match('@HTTP.+200@', $img_head[0]) ) throw new \Exception("CalendarExtractor.__construct(, , ) received but cannot reach "); /* (3) Check @start_d format */ if( !preg_match("@^\d{1,2}-\d{1,2}-\d{3,}$@", $start_d) ) throw new \Exception("CalendarExtractor.__construct(, , ) received has not the correct format"); /* (4) Check @d_uid format */ if( !preg_match("@^T\d+$@", $d_uid) ) throw new \Exception("CalendarExtractor.__construct(, , ) received 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->d_uid = $d_uid; $this->start_d = $start_d; } } /* (2) Extracts calendar data from image * * @return error 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) 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 = []; } } /* [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; } } /* [3] For each day -> get events =========================================================*/ { $uid = 0; /* (1) For each day */ for( $day_n = 0 ; $day_n < count($col_ind)-1 ; $day_n++ ){ $col_x = $col_ind[$day_n]; /* (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); $p1e = '#'.dechex($p1); /* (4) If on black pixel and next not white */ if( $p == 0 && $p1 != 0xffffff ){ // {1} calculate time // $start_y = $y; $time = $this->yToTime($day_n, $start_y); // {2} Incr uid // $uid++; // {3} Store event start // $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 // $this->event[$uid][$time] = $this->yToTime($day_n, $y); // {6} Exctract event's image // $this->extractEvent("$time-$uid", [$col_x, $start_y+1], [$col_ind[$day_n+1]-1, $y]); } } } } /* [4] Save db changes =========================================================*/ /* (1) Update data */ $ldb->delete($this->d_uid); $ldb->insert($this->d_uid, $d_db); /* (2) Close connection */ $ldb->close(); } /* (3) Exctracts an event * * @uid Image uid * @start Start rect (x, y) * @stop Stop rect (x, y) * ---------------------------------------------------------*/ public function extractEvent($uid, $start=null, $stop=null){ /* [1] Get the right clip =========================================================*/ /* (1) Create clipped copy */ $clip = \imagecreatetruecolor($stop[0]-$start[0], $stop[1]-$start[1]); $copied = \imagecopyresized( $clip, // destin img $this->img_res, // source img 0, // dest x 0, // dest y $start[0], // src x $start[1], // src y $stop[0]-$start[0], // dest w $stop[1]-$start[1], // dest h $stop[0]-$start[0], // src w $stop[1]-$start[1] // src h ); /* (2) Manage copy error */ if( !$copied ) throw new \Exception("Cannot clip image"); /* (3) Save to file */ \imagesavealpha($clip, true); if( !\imagejpeg($clip, __ROOT__."/tmp/$uid.jpeg") ) throw new \Exception("Cannot save image"); /* [2] Process OCR =========================================================*/ // TODO: } /* (3) Get a pixel's color * * @x X coordinate * @y Y coordinate * * @return color Raw color * ---------------------------------------------------------*/ private function getColor($x, $y){ return imagecolorat($this->img_res, $x, $y); } /* (4) Get time from a y-coordinate * * @day_n Day relative index * @y y Coordinate * * @return time 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 */ $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 */ $min = round($min/10)*10; /* (5) Format to 2-digit */ $hour = ( $hour < 10 ) ? "0$hour" : $hour; $min = ( $min < 10 ) ? "0$min" : $min ; } /* [3] Convert to GMT (UTC+0) =========================================================*/ /* (1) Set fixed timezone offset */ $tz_offset = +2; /* (2) Get GMT (UTC+0) timestamp */ $ts = strtotime("${day} $hour:$min:00") - (3600*$tz_offset); /* (3) Return GMT date */ return date("Ymd\THis\Z", $ts); } /* (5) Generate ICS output * * @return ics ICS Representation of the events * ---------------------------------------------------------*/ public function toIcs(){ $RAW = ""; /* [1] Get light-database =========================================================*/ /* (1) Create/Open database */ try{ $ldb = new lightdb('config'); /* (2) Manage error */ }catch(\Exception $e){ throw new \Exception("Cannot access database"); } /* (3) Get color association if available */ $col_assoc = []; if( !is_null($ldb->index($this->d_uid)) ) $col_assoc = $ldb->fetch($this->d_uid); // var_dump($col_assoc); // die(1); /* [2] For each event =========================================================*/ foreach($this->event as $event_col=>$events){ $type = "unknown"; if( isset($col_assoc[$event_col]) ) $type = $col_assoc[$event_col]; /* (2) For each event of each type ---------------------------------------------------------*/ foreach($events as $start_t=>$stop_t){ $RAW .= "BEGIN:VEVENT\n"; $RAW .= "DTSTAMP:".gmdate("Ymd\THis\Z", time())."\n"; // required $RAW .= "DTSTART:${start_t}\n"; $RAW .= "DTEND:${stop_t}\n"; $RAW .= "UID:$start_t-univ-pau-ics\n"; // required $RAW .= "SUMMARY:$type\n"; $RAW .= "CATEGORIES: UPPA Calendar\n"; $RAW .= "END:VEVENT\n"; } } return $RAW; } }