fontArial = resource_path('br_generation/fonts/arial.ttf'); $this->fontArialBd = resource_path('br_generation/fonts/arialbd.ttf'); $this->fontImpact = resource_path('br_generation/fonts/impact.ttf'); $this->imgHand = resource_path('br_generation/images/hand.png'); $this->imgMask = resource_path('br_generation/images/mask.png'); // FIXME : Implementer gestion de cache pour ne pas regénérer ce qui est générique au coupon. $this->mask = \imagecreatefrompng($this->imgMask); $this->coupon = $coupon; $this->campaign = $campaign; $this->customer = $customer; $this->printUniqId = $printUniqId; } /** * Generate coupon picture and return base64 * * @return string * @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException. * @throws \Psr\Container\NotFoundExceptionInterface NotFoundExceptionInterface. * @throws \Psr\Container\ContainerExceptionInterface ContainerExceptionInterface. */ public function generate(): string { // Generic. $this->addHand(); $this->addAmount(); $this->addWatermark(); $this->addValidOn(); $this->addDecoImg(); $this->addLogoImg(); // End Generic. // User Specific. $this->addLegalNotice(); $this->addCustomerInfos(); $this->addCustomerBarcode(); $this->addCouponBarcode(); // End User Specific. // Date Specific. $this->addValidityPeriod(); // End Date Specific. ob_start(); imagejpeg($this->mask, null, 100); $br = ob_get_contents(); ob_end_clean(); imagedestroy($this->mask); return "data:image/jpeg;base64," . base64_encode($br); } /** * Add coupom barcode into mask var * * used datas : * - customer country * - coupon gs1 * - coupon process_code * * @return void * @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException. */ private function addCouponBarcode(): void { // Nom du centre de traitement. if ($this->customer->country !== Country::france->value) { $textReduc = "Traitement ScanCoupon/HighCo Data Benelux"; } else { $textReduc = "• Traitement ScanCoupon •"; } $ImageFond = imagecreate(270, 20); imagecolorallocate($ImageFond, 255, 255, 255); $black = imagecolorallocate($ImageFond, 0, 0, 0); imagettftext($ImageFond, 9, 0, 0, 10, $black, $this->fontArialBd, $textReduc); if ($this->customer->country !== 250) { imagecopy($this->mask, $ImageFond, 60, 230, 0, 0, imagesx($ImageFond), imagesy($ImageFond)); } else { imagecopy($this->mask, $ImageFond, 110, 322, 0, 0, imagesx($ImageFond), imagesy($ImageFond)); } imagedestroy($ImageFond); // Left barcode. if ($this->customer->country !== 250) { $codeBarre = imagecreatefromjpeg(storage_path($this->coupon->gs1)); imageresolution($codeBarre, 72); list($width, $height) = getimagesize(storage_path($this->coupon->gs1)); $r = $width / $height; $w = 285; $h = 150; if ($w / $h > $r) { $newwidth = $h * $r; $newheight = $h; } else { $newheight = $w / $r; $newwidth = $w; } $test = imagecreatetruecolor($newwidth, $newheight); imagecopyresampled($test, $codeBarre, 0, 0, 0, 0, $newwidth, $newheight, $width, $height); imagecopy($this->mask, $test, 60, 250, 0, 0, imagesx($test), imagesy($test)); } else { $codeBarre = $this->coupon->process_code; $generator = new BarcodeGeneratorPNG(); $base64 = $generator->getBarcode($codeBarre, $generator::TYPE_CODE_128_A, 2, 46); $barcodeImage = imagecreatefromstring($base64); imagecopy($this->mask, $barcodeImage, 10, 342, 0, 0, imagesx($barcodeImage), imagesy($barcodeImage)); $ImageFond = imagecreate(380, 15); imagecolorallocate($ImageFond, 255, 255, 255); $black = imagecolorallocate($ImageFond, 0, 0, 0); imagettftext($ImageFond, 11, 0, 0, 14, $black, $this->fontArial, $codeBarre); imagecopy($this->mask, $ImageFond, 135, 390, 0, 0, imagesx($ImageFond), imagesy($ImageFond)); } //end if imagedestroy($ImageFond); // End left barcode. } /** * Add customer barcode from printUniqId into mask var * * @return void */ private function addCustomerBarcode(): void { // Right barcode. $barcode = str_pad($this->printUniqId, 13, "0", STR_PAD_LEFT); $generator = new BarcodeGeneratorPNG(); $base64 = $generator->getBarcode($barcode, $generator::TYPE_CODE_128_A, 1, 46); $barcodeImage = imagecreatefromstring($base64); imagecopy($this->mask, $barcodeImage, 730, 342, 0, 0, imagesx($barcodeImage), imagesy($barcodeImage)); // Text. $ImageFond = imagecreate(110, 15); imagecolorallocate($ImageFond, 255, 255, 255); $black = imagecolorallocate($ImageFond, 0, 0, 0); imagettftext($ImageFond, 11, 0, 0, 14, $black, $this->fontArial, $barcode); imagecopy($this->mask, $ImageFond, 800, 390, 0, 0, imagesx($ImageFond), imagesy($ImageFond)); // End text. // End right barcode. } /** * Add validity period from coupon validity_period into mask var * * @return void * @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException. * @throws \Psr\Container\NotFoundExceptionInterface NotFoundExceptionInterface. * @throws \Psr\Container\ContainerExceptionInterface ContainerExceptionInterface. */ private function addValidityPeriod(): void { // Inscription de la date de validité. $ImageFond = imagecreate(120, 40); $white = imagecolorallocate($ImageFond, 255, 255, 255); $black = imagecolorallocate($ImageFond, 0, 0, 0); imagettftext($ImageFond, 8, 0, 1, 8, $black, $this->fontArialBd, sprintf("%s : ", trans("Valable jusqu'au"))); imagettftext( $ImageFond, 8, 0, 20, 23, $black, $this->fontArial, Carbon::now()->addDays($this->coupon->validity_period)->format("d/m/Y") ); imagecolortransparent($ImageFond, $white); imagecopy($this->mask, $ImageFond, 780, 142, 0, 0, imagesx($ImageFond), imagesy($ImageFond)); imagedestroy($ImageFond); } /** * Add customer infos into mask var * * used datas : * - customer firstname * - customer lastname * - customer address * - customer postcode * - customer city * - printUniqId * * @return void */ private function addCustomerInfos(): void { $libelle = "OFFRE RÉSERVÉE À"; $user = sprintf( "%s %s\r\n%s\r\n%s\r\n%s\r\nid %s", $this->customer->firstname, $this->customer->lastname, $this->customer->address, $this->customer->postcode, $this->customer->city, str_pad($this->printUniqId, 13, "0", STR_PAD_LEFT) ); $ImageFond = imagecreate(120, 80); $white = imagecolorallocate($ImageFond, 255, 255, 255); $black = imagecolorallocate($ImageFond, 0, 0, 0); $box1 = imagettfbbox(8, 0, $this->fontArial, $user); $box2 = imagettfbbox(8, 0, $this->fontArial, $libelle); imagettftext( $ImageFond, 8, 0, (120 / 2) - (abs($box2[4]) - abs($box2[6])) / 2, 10, $black, $this->fontArialBd, $libelle ); imagettftext( $ImageFond, 8, 0, (120 / 2) - (abs($box1[4]) - abs($box1[6])) / 2, 25, $black, $this->fontArial, $user ); imagecolortransparent($ImageFond, $white); imagecopy($this->mask, $ImageFond, 770, 40, 0, 0, imagesx($ImageFond), imagesy($ImageFond)); imagedestroy($ImageFond); } /** * Add logo picture from brand logo into mask var * * @return void * @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException. */ private function addLogoImg(): void { // ---- Copie le logo dans le mask $logo = imagecreatefromjpeg(storage_path($this->campaign->brand->logo)); imagealphablending($this->mask, true); imagesavealpha($this->mask, true); imagecopy($this->mask, $logo, 767, 220, 0, 0, imagesx($logo), imagesy($logo)); imagedestroy($logo); imagedestroy($logo); } /** * add decoration picture from coupon decoration into mask var * * @return void * @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException. */ private function addDecoImg(): void { // Copie l'image de decoration dans le mask. $pdt = imagecreatefromjpeg(storage_path($this->coupon->decoration)); imagealphablending($this->mask, true); imagesavealpha($this->mask, true); imagecopy($this->mask, $pdt, 40, 10, 0, 0, imagesx($pdt), imagesy($pdt)); imagedestroy($pdt); } /** * Add valid on legal text from coupon valid_on into mask var * * @return void */ private function addValidOn(): void { $maxCharByLines = 64; $ImageFond = imagecreate(387, 200); $white = imagecolorallocate($ImageFond, 255, 255, 255); $black = imagecolorallocate($ImageFond, 0, 0, 0); $textReducs = explode("\r\n", str_replace("
", "\r\n", $this->coupon->valid_on)); $y = 14; foreach ($textReducs as $line) { foreach (str_split($line, $maxCharByLines) as $sLine) { $this->imagettftextSp($ImageFond, 10, 0, 0, $y, $black, $this->fontArialBd, $sLine, 0.01); $y += 12; } } imagecolortransparent($ImageFond, $white); imagecopy($this->mask, $ImageFond, 360, 170, 0, 0, imagesx($ImageFond), imagesy($ImageFond)); imagedestroy($ImageFond); } /** * Add watermark into mask var * * used datas : * - brand name * - coupon amount * * @return void */ private function addWatermark(): void { // Inscription filigrane. $watermark = sprintf( "%s %s €", strtoupper($this->campaign->brand->name), number_format($this->coupon->amount, 2, ",", " ") ); $line_filigramme = ""; $textFili = ""; for ($i = 0; $i < 11; $i++) { $line_filigramme .= $watermark . " "; } $line_filigramme .= "\r\n"; for ($i = 0; $i < 30; $i++) { $textFili .= $line_filigramme; } $textFiliLines = explode("\r\n", $textFili); $ImageFond = imagecreate(402, 240); $white = imagecolorallocate($ImageFond, 255, 255, 255); $black = imagecolorallocate($ImageFond, 0, 0, 0); $y = 0; foreach ($textFiliLines as $textFiliLine) { $y += 20; $this->imagettftextSp($ImageFond, 11, 25, -100, $y, $black, $this->fontArial, $textFiliLine, 0.01); } imagecolortransparent($ImageFond, $white); imagecopymerge($this->mask, $ImageFond, 349, 1, 0, 0, imagesx($ImageFond), imagesy($ImageFond), 30); imagedestroy($ImageFond); } /** * Add amount from coupon amount into mask var * * @return void */ private function addAmount(): void { // ---- Inscription du montant du BR $textMontant = number_format($this->coupon->amount, 2, ",", " "); $textEuro = "€"; $libReduc = "DE RÉDUCTION IMMÉDIATE"; $ImageFond = imagecreate(265, 200); $white = imagecolorallocate($ImageFond, 255, 255, 255); $blue = imagecolorallocate($ImageFond, 8, 169, 223); $grey = imagecolorallocate($ImageFond, 219, 219, 221); $this->imagettftextContour( $ImageFond, 95, 0, 5, 110, $grey, $this->fontImpact, $textMontant, $blue, 3, 3, 3, 3 ); $this->imagettftextContour($ImageFond, 50, 0, 220, 55, $grey, $this->fontArial, $textEuro, $blue, 2, 2, 2, 2); $this->imagettftextContour($ImageFond, 16, 0, 0, 150, $grey, $this->fontImpact, $libReduc, $blue, 1, 1, 1, 1); imagecolortransparent($ImageFond, $white); imagecopy($this->mask, $ImageFond, 360, 10, 0, 0, imagesx($ImageFond), imagesy($ImageFond)); imagedestroy($ImageFond); } /** * Add hand into mask var * * @return void */ private function addHand(): void { // Copie la main dans le mask. $hand = imagecreatefrompng($this->imgHand); imagecopy($this->mask, $hand, 577, 2, 0, 0, imagesx($hand), imagesy($hand)); imagealphablending($this->mask, false); imagesavealpha($this->mask, true); imagedestroy($hand); } /** * Add legal notice into mask var using writeLegalNotice method, taking account multiple factors * * used datas : * - coupon legal_notices * - customer country * - brand rcs * - brand contact_mail * * @return void * @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException. * @throws \Psr\Container\NotFoundExceptionInterface NotFoundExceptionInterface. * @throws \Psr\Container\ContainerExceptionInterface ContainerExceptionInterface. */ private function addLegalNotice(): void { // Si on trouve la pseudo balise alors on a les mentions internationales. if (strpos($this->coupon->legal_notices, "")) { $legalNotices = explode('', $this->coupon->legal_notices); // Si le customer ne viens pas de France. if ($this->customer->country !== Country::france->value) { $this->writeLegalNotice(sprintf( "%s\r\n%s\r\n%s", $legalNotices[0], $legalNotices[1], $this->campaign->brand->rcs ), $this->campaign->brand->contact_mail); } else { $this->writeLegalNotice(sprintf( "%s\r\n%s", $legalNotices[0], $this->campaign->brand->rcs ), $this->campaign->brand->contact_mail); } } else { // Si on ne trouve pas la pseudo balise alors on a que du FR. $this->writeLegalNotice(sprintf( "%s\r\n%s", $this->coupon->legal_notices, $this->campaign->brand->rcs ), $this->campaign->brand->contact_mail); } //end if } /** * Write legal notice into mask var * * @param string $legalNotice * @param string $contactMail * @return void * @throws \Illuminate\Contracts\Container\BindingResolutionException. BindingResolutionException. * @throws \Psr\Container\NotFoundExceptionInterface NotFoundExceptionInterface. * @throws \Psr\Container\ContainerExceptionInterface ContainerExceptionInterface. */ private function writeLegalNotice(string $legalNotice, string $contactMail): void { $maxCharByLines = 103; $ImageMentionFond = imagecreate(420, 145); $white = imagecolorallocate($ImageMentionFond, 255, 255, 255); imagefilledrectangle($ImageMentionFond, 0, 0, 414, 99, $white); $black = imagecolorallocate($ImageMentionFond, 0, 0, 0); $lines_mentions = explode("\r\n", $legalNotice); $y = 19; foreach ($lines_mentions as $line) { foreach (str_split($line, $maxCharByLines) as $sLine) { $this->imagettftextSp($ImageMentionFond, 7, 0, 15, $y, $black, $this->fontArial, $sLine, 0.01); $y += 9; } } $this->imagettftextSp( $ImageMentionFond, 7, 0, 15, $y, $black, $this->fontArialBd, sprintf("%s : %s", trans('Renseignements'), $contactMail), 0.01 ); imagecopy( $this->mask, $ImageMentionFond, 335, 235, 0, 0, imagesx($ImageMentionFond), imagesy($ImageMentionFond) ); imagedestroy($ImageMentionFond); } /** * Create picture from text Contour * * @todo Définir le sens de contour * @todo remettre au propre les types du proto * * @param mixed $image * @param mixed $fontsize * @param mixed $angle * @param mixed $x * @param mixed $y * @param mixed $color * @param mixed $font * @param mixed $text * @param mixed $color_contour * @param integer $contour_haut * @param integer $contour_bas * @param integer $contour_gauche * @param integer $contour_droite * @return void */ private function imagettftextContour( mixed $image, mixed $fontsize, mixed $angle, mixed $x, mixed $y, mixed $color, mixed $font, mixed $text, mixed $color_contour, int $contour_haut = 1, int $contour_bas = 1, int $contour_gauche = 1, int $contour_droite = 1 ): void { $coords_x = []; $coords_y = []; for ($i_y = -$contour_haut; $i_y <= $contour_bas; $i_y++) { $y_temp = array_fill(0, $contour_gauche + $contour_droite + 1, $i_y); $x_temp = []; for ($i_x = -$contour_gauche; $i_x <= $contour_droite; $i_x++) { $x_temp[] = $i_x; } $coords_x = array_merge($coords_x, $x_temp); $coords_y = array_merge($coords_y, $y_temp); } $c = count($coords_x); for ($i = 0; $i < $c; $i++) { imagettftext( $image, $fontsize, $angle, $x + $coords_x[$i], $y + $coords_y[$i], $color_contour, $font, $text ); } imagettftext($image, $fontsize, $angle, $x, $y, $color, $font, $text); } /** * Create picture from text Sp * * @todo définir Sp * @todo remettre au propre les types du proto * * @param mixed $image * @param mixed $size * @param mixed $angle * @param mixed $x * @param mixed $y * @param mixed $color * @param mixed $font * @param mixed $text * @param integer $spacing * @return void */ private function imagettftextSp( mixed $image, mixed $size, mixed $angle, mixed $x, mixed $y, mixed $color, mixed $font, mixed $text, int $spacing = 0 ): void { if ($spacing == 0) { imagefttext($image, $size, $angle, $x, $y, $color, $font, $text); } else { $temp_x = $x; $temp_y = $y; // To avoid special char problems. $char_array = preg_split('//u', $text, -1, PREG_SPLIT_NO_EMPTY); foreach ($char_array as $char) { imagefttext($image, $size, $angle, $temp_x, $temp_y, $color, $font, $char); $bbox = imagettfbbox($size, 0, $font, $char); $temp_x += cos(deg2rad($angle)) * ($spacing + ($bbox[2] - $bbox[0])); $temp_y -= sin(deg2rad($angle)) * ($spacing + ($bbox[2] - $bbox[0])); } } } /** * Check if a coupon attached to a wall campaign is used * * @param \App\Models\Coupon $coupon * @param \App\Models\Campaign $campaign * @param \App\Models\Customer $customer * @return boolean */ public static function wallCouponIsUsed(Coupon $coupon, Campaign $campaign, Customer $customer): bool { // FIXME : Revoir la règle de gestion et donc l'implémentation. $isUsed = false; // ---- Contrôle le nombre limite d'impression if ($coupon->limit_qty > 0) { $count = PrintedWall::where( [ ['campaign_id', '=', $campaign->id], ['coupon_id', '=', $coupon->id], ['customer_id', '=', $customer->id] ] )->count(); if ($count >= $coupon->limit_qty) { $isUsed = true; } } // ---- Contrôle la limite de période de diffusion if ($coupon->limit_period > 0) { $count = PrintedWall::where( [ ['campaign_id', '=', $campaign->id], ['coupon_id', '=', $coupon->id], ['customer_id', '=', $customer->id] ] )->orderBy('created_at', 'DESC')->first(); if ($count && $count->count() > 0) { if ((new Carbon($count->created_at))->addDays($coupon->limit_period)->greaterThan(Carbon::now())) { $isUsed = true; } } } return $isUsed; } }