main_keyword; $title = $post->short_title; $article_type = $post->type; $country_iso = 'US'; $country_name = get_country_name_by_iso($country_iso); $images = []; $client = new DFSClient( config('dataforseo.login'), config('dataforseo.password'), config('dataforseo.timeout'), config('dataforseo.api_version'), config('dataforseo.url'), ); // You will receive SERP data specific to the indicated keyword, search engine, and location parameters $serp_model = new SettingSerpLiveAdvanced(); $serp_model->setSe('google'); $serp_model->setSeType('images'); $serp_model->setKeyword($keyword); $serp_model->setLocationName($country_name); $serp_model->setDepth(100); $serp_model->setLanguageCode('en'); $serp_res = $serp_model->getAsJson(); // try { $serp_obj = json_decode($serp_res, false, 512, JSON_THROW_ON_ERROR); //dd($serp_obj); if ($serp_obj?->status_code == 20000) { $json_file_name = config('platform.dataset.news.images_serp.file_prefix').str_slug($keyword).'-'.epoch_now_timestamp().'.json'; $upload_status = OSSUploader::uploadJson( config('platform.dataset.news.images_serp.driver'), config('platform.dataset.news.images_serp.path'), $json_file_name, $serp_obj); if ($upload_status) { $news_serp_result = new NewsSerpResult(); $news_serp_result->serp_provider = 'dfs'; $news_serp_result->serp_se = 'google'; $news_serp_result->serp_se_type = 'images'; $news_serp_result->serp_keyword = $keyword; $news_serp_result->serp_country_iso = strtoupper($country_iso); $news_serp_result->serp_cost = $serp_obj?->cost; $news_serp_result->result_count = $serp_obj?->tasks[0]?->result[0]?->items_count; $news_serp_result->filename = $json_file_name; $news_serp_result->status = 'initial'; if ($news_serp_result->save()) { $serp_items = $serp_obj?->tasks[0]?->result[0]?->items; //dd($serp_items); foreach ($serp_items as $item) { if ($item->type == 'images_search') { //dd($item); $images[] = $item->source_url; if (count($images) > 20) { break; } } } } //return $news_serp_result; } else { throw new Exception('Uploading failed', 1); } } else { throw new Exception('Data failed', 1); } // } catch (Exception $e) { // return null; // } $numImagesInCanvas = 2; if ($numImagesInCanvas > count($images)) { $numImagesInCanvas = count($images); } $canvasWidth = 720; $canvasHeight = 405; $canvas = Image::canvas($canvasWidth, $canvasHeight); // Add Images $imageWidth = $canvasWidth / $numImagesInCanvas; // Process and place each image $xOffset = 0; // Horizontal offset to place each image for ($i = 0; $i < count($images); $i++) { $url = $images[$i]; try { $imageResponse = Http::timeout(300)->withHeaders([ 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36', ])->get($url); $imageContent = $imageResponse->body(); $image = Image::make($imageContent) ->resize(null, $canvasHeight, function ($constraint) { $constraint->aspectRatio(); }) ->resizeCanvas($imageWidth, $canvasHeight, 'center', false, [255, 255, 255, 0]); //->blur(6) $canvas->insert($image, 'top-left', $xOffset, 0); $xOffset += $imageWidth; } catch (Exception $e) { continue; } } /// $fontSize = 28; $articleTypeFontSize = 24; $padding = 15; $fontPath = resource_path('fonts/Inter/Inter-Black.ttf'); // Split title into words and reconstruct lines $words = explode(' ', $title); $lines = ['']; $currentLineIndex = 0; foreach ($words as $word) { $potentialLine = $lines[$currentLineIndex] ? $lines[$currentLineIndex].' '.$word : $word; $box = imagettfbbox($fontSize, 0, $fontPath, $potentialLine); $textWidth = abs($box[2] - $box[0]); if ($textWidth < $canvasWidth * 0.9) { $lines[$currentLineIndex] = $potentialLine; } else { $currentLineIndex++; $lines[$currentLineIndex] = $word; } } // Calculate the dimensions of the article_type text $articleTypeBox = imagettfbbox($articleTypeFontSize, 0, $fontPath, $article_type); $articleTypeWidth = abs($articleTypeBox[2] - $articleTypeBox[0]); $articleTypeHeight = abs($articleTypeBox[7] - $articleTypeBox[1]); // Define the start Y position for the article type overlay $articleOverlayStartY = $canvasHeight - ($fontSize * count($lines)) - ($articleTypeHeight + 4 * $padding); // Create the blue overlay for the article type $overlayWidth = $articleTypeWidth + 2 * $padding; $canvas->rectangle(20, $articleOverlayStartY, 10 + $overlayWidth, $articleOverlayStartY + $articleTypeHeight + 2 * $padding, function ($draw) { $draw->background([255, 255, 255, 0.8]); }); // Overlay the article_type text within its overlay, centered horizontally and vertically $textStartX = 20 + ($overlayWidth - $articleTypeWidth) / 2; // Center the text horizontally $canvas->text(strtoupper($article_type), $textStartX, $articleOverlayStartY + ($articleTypeHeight + 2 * $padding) / 2, function ($font) use ($articleTypeFontSize, $fontPath) { $font->file($fontPath); $font->size($articleTypeFontSize); $font->color('#0000FF'); $font->align('left'); $font->valign('middle'); // This ensures the text is vertically centered within the overlay }); // Create the blue overlay for the title $titleOverlayStartY = $articleOverlayStartY + $articleTypeHeight + 2 * $padding; $canvas->rectangle(0, $titleOverlayStartY, $canvasWidth, $canvasHeight, function ($draw) { $draw->background([0, 0, 255, 0.5]); }); // Draw each line for the title $yPosition = $titleOverlayStartY + $padding; foreach ($lines as $line) { $canvas->text($line, $canvasWidth / 2, $yPosition, function ($font) use ($fontSize, $fontPath) { $font->file($fontPath); $font->size($fontSize); $font->color('#FFFFFF'); $font->align('center'); $font->valign('top'); }); $yPosition += $fontSize + $padding; } $epoch_now_timestamp = epoch_now_timestamp(); $filename = $post->slug.'-'.$epoch_now_timestamp.'.jpg'; $ok = OSSUploader::uploadFile('r2', 'post_images/', $filename, (string) $canvas->stream('jpeg')); // LQIP // Clone the main image for LQIP version $lqipImage = clone $canvas; // Apply blur $lqipImage->blur(5); // Adjust to the desired blur level // Pixelate the image $lqipImage->pixelate(30); // Adjust this value based on the desired pixelation level // Encode the image to a low-quality JPG $lqipImage->encode('webp', 5); // LQIP filename $lqip_filename = $post->slug.'-'.$epoch_now_timestamp.'_lqip.webp'; // Upload the LQIP version using OSSUploader $lqip_ok = OSSUploader::uploadFile('r2', 'post_images/', $lqip_filename, (string) $lqipImage->stream('webp')); if ($ok && $lqip_ok) { $post->featured_image = 'post_images/'.$filename; $post->status = 'publish'; $post->save(); PublishIndexPostJob::dispatch($post)->onQueue('default')->onConnection('default'); return $post; } return null; } }