first commit
This commit is contained in:
324
plugins/openai_image_edit/pages/edit.php
Executable file
324
plugins/openai_image_edit/pages/edit.php
Executable file
@@ -0,0 +1,324 @@
|
||||
<?php
|
||||
include "../../../include/boot.php";
|
||||
include "../../../include/authenticate.php";
|
||||
|
||||
|
||||
if (!in_array("openai_gpt" ,$plugins) || !in_array("openai_image_edit", $plugins))
|
||||
{
|
||||
exit("The OpenAI GPT and OpenAI Image Editing plugins must be enabled and configured.");
|
||||
}
|
||||
|
||||
// Find image
|
||||
$ref=getval("ref",0,true);
|
||||
$access=get_resource_access($ref);
|
||||
$edit_access=get_edit_access($ref);
|
||||
|
||||
if ($access!=0)
|
||||
{
|
||||
// They shouldn't arrive here as the link wouldn't be available.
|
||||
exit("Access denied");
|
||||
}
|
||||
|
||||
function curlprogress($resource,$download_size, $downloaded, $upload_size, $uploaded)
|
||||
{
|
||||
// Give an estimate of completion based on the % of upload. There is also the DALL-E 2 processing time but the bulk of the time seems to be the upload due to using PNG for images.
|
||||
global $lang;
|
||||
if ($uploaded>0)
|
||||
{
|
||||
$percent=floor(($uploaded/$upload_size)*100);
|
||||
$percent*=7;$percent+=10; // It lags behind a lot, after experimentation, this gives a more reasonable estimate of completion time.
|
||||
if ($percent>=100)
|
||||
{
|
||||
set_processing_message($lang["openai_image_edit__completing"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_processing_message($lang["openai_image_edit__sending"] . " (" . $percent . "%)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
|
||||
set_processing_message($lang["openai_image_edit__preparing_images"]);
|
||||
|
||||
$maskData = getval('mask',''); // Base64 encoded mask from the frontend
|
||||
$mode = getval('mode','');
|
||||
$prompt = getval('prompt','');
|
||||
|
||||
// Decode the mask data from base64
|
||||
list($type, $maskData) = explode(';', $maskData);
|
||||
list(, $maskData) = explode(',', $maskData);
|
||||
$maskData = base64_decode($maskData);
|
||||
|
||||
if ($mode=="white" || $mode=="black")
|
||||
{
|
||||
$mask=imagecreatefromstring($maskData);
|
||||
|
||||
// Get the width and height of the image
|
||||
$width = imagesx($mask);
|
||||
$height = imagesy($mask);
|
||||
|
||||
// Create a new true color image with the same dimensions
|
||||
$newBackground = imagecreatetruecolor($width, $height);
|
||||
|
||||
// Fill the new image with colour
|
||||
$shade=255;
|
||||
if ($mode=="black") {$shade=0;}
|
||||
$fill = imagecolorallocate($newBackground, $shade, $shade, $shade);
|
||||
imagefill($newBackground, 0, 0, $fill);
|
||||
|
||||
// Copy the original image onto the white background
|
||||
// This will replace transparent areas with white
|
||||
imagecopy($newBackground, $mask, 0, 0, 0, 0, $width, $height);
|
||||
|
||||
// Start output buffering to capture the image data in memory
|
||||
ob_start();
|
||||
imagepng($newBackground);
|
||||
$imagedata = ob_get_clean();
|
||||
|
||||
// Free up memory
|
||||
imagedestroy($mask);
|
||||
imagedestroy($newBackground);
|
||||
|
||||
// Return the image data as JSON with base64 encoding
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(["image_base64" => base64_encode($imagedata)]);
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($mode=="clone")
|
||||
{
|
||||
$mask=imagecreatefromstring($maskData);
|
||||
|
||||
// Get the width and height of the image
|
||||
$width = imagesx($mask);
|
||||
$height = imagesy($mask);
|
||||
|
||||
// Create a new true color image with the same dimensions
|
||||
$image = imagecreatefromstring($maskData);
|
||||
imagealphablending($image, true);
|
||||
imagesavealpha($image, true);
|
||||
|
||||
// Clone parts of the surrounding image by moving it in an ever decreasing box
|
||||
for ($offset=300;$offset>0;$offset-=30)
|
||||
{
|
||||
imagecopy($image, $mask, -$offset, 0, 0, 0, $width, $height);
|
||||
imagecopy($image, $mask, 0, -$offset, 0, 0, $width, $height);
|
||||
imagecopy($image, $mask, $offset, 0, 0, 0, $width, $height);
|
||||
imagecopy($image, $mask, 0, $offset, 0, 0, $width, $height);
|
||||
}
|
||||
imagecopy($image, $mask, 0, 0, 0, 0, $width, $height);
|
||||
|
||||
// Start output buffering to capture the image data in memory
|
||||
ob_start();
|
||||
imagepng($image);
|
||||
$imagedata = ob_get_clean();
|
||||
|
||||
// Free up memory
|
||||
imagedestroy($mask);
|
||||
imagedestroy($image);
|
||||
|
||||
// Return the image data as JSON with base64 encoding
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(["image_base64" => base64_encode($imagedata)]);
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
// Prepare the OpenAI API request using multipart/form-data
|
||||
if ($mode=="edit")
|
||||
{
|
||||
$url = 'https://api.openai.com/v1/images/edits';
|
||||
$model = "dall-e-2";
|
||||
$content_type="multipart/form-data";
|
||||
}
|
||||
if ($mode=="variation")
|
||||
{
|
||||
$url = 'https://api.openai.com/v1/images/variations';
|
||||
$model = "dall-e-2";
|
||||
$content_type="multipart/form-data";
|
||||
}
|
||||
if ($mode=="generate")
|
||||
{
|
||||
$url = 'https://api.openai.com/v1/images/generations';
|
||||
$model = "dall-e-3";
|
||||
$content_type="application/json";
|
||||
}
|
||||
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'curlprogress');
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
"Authorization: Bearer $openai_gpt_api_key",
|
||||
"Content-Type: " . $content_type
|
||||
]);
|
||||
|
||||
|
||||
// Improve the mask by replacing non transparent areas with black. This significantly reduces the time to send the mask to OpenAI as the compression is much better.
|
||||
$mask=imagecreatefromstring($maskData);
|
||||
// Set blending mode off to preserve transparency
|
||||
imagealphablending($mask, false);
|
||||
imagesavealpha($mask, true);
|
||||
|
||||
// Get image dimensions
|
||||
$width = imagesx($mask);
|
||||
$height = imagesy($mask);
|
||||
|
||||
// Loop through each pixel
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
for ($y = 0; $y < $height; $y++) {
|
||||
// Get the color and alpha of the current pixel
|
||||
$rgba = imagecolorat($mask, $x, $y);
|
||||
$alpha = ($rgba & 0x7F000000) >> 24;
|
||||
|
||||
// Set the pixel to black with the same alpha
|
||||
$black = imagecolorallocatealpha($mask, 0, 0, 0, $alpha);
|
||||
imagesetpixel($mask, $x, $y, $black);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-render the mask
|
||||
ob_start();
|
||||
imagepng($mask);
|
||||
$maskDataSimplified = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
// Prepare the data array using CURLFile for both image and mask
|
||||
$data = [
|
||||
'model' => $model, // Specify model (if applicable)
|
||||
'n' => 1,
|
||||
'size' => '1024x1024'
|
||||
];
|
||||
|
||||
if ($mode=="edit" || $mode=="variation")
|
||||
{
|
||||
$data['image'] = new CURLStringFile($maskData, 'image/png');
|
||||
}
|
||||
|
||||
if ($mode=="edit" || $mode=="generate")
|
||||
{
|
||||
$data['prompt'] = $prompt;
|
||||
}
|
||||
|
||||
if ($mode=="edit")
|
||||
{
|
||||
$data['mask'] = new CURLStringFile($maskDataSimplified, 'image/png');
|
||||
}
|
||||
|
||||
if ($mode=="generate")
|
||||
{
|
||||
$data=json_encode($data);
|
||||
}
|
||||
|
||||
// Attach the form data
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
||||
|
||||
// Execute the request and get the response
|
||||
$response = curl_exec($ch);
|
||||
|
||||
// Check for errors in the cURL request
|
||||
if (curl_errno($ch)) {
|
||||
echo 'Error:' . curl_error($ch);
|
||||
} else {
|
||||
$json=json_decode($response,true);
|
||||
$url=$json["data"][0]["url"] ?? "";
|
||||
if ($url!="")
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(["image_base64"=>base64_encode(file_get_contents($url))]);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $response;
|
||||
}
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
exit();
|
||||
}
|
||||
|
||||
include "../../../include/header.php";
|
||||
?>
|
||||
|
||||
<div class="BasicsBox">
|
||||
<?php
|
||||
renderBreadcrumbs([
|
||||
[
|
||||
"title" => $lang["backtoview"],
|
||||
"href" => generateURL($baseurl_short . "pages/view.php", ["ref" => $ref])
|
||||
],
|
||||
[
|
||||
"title" => $lang["openai_image_edit__edit_with_ai"],
|
||||
"help" => "plugins/openai_image_edit"
|
||||
]
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<img id="image" src="get_png.php?ref=<?php echo (int) $ref ?>" alt="" hidden>
|
||||
<div id="canvas-container" class="canvas-container" style="position: relative;visibility:hidden;">
|
||||
<canvas id="canvas"></canvas>
|
||||
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; pointer-events: none;"></canvas>
|
||||
</div>
|
||||
|
||||
<div id="toolbox" class="toolbox openai-image-edit" style="visibility:hidden;">
|
||||
<div id="tools">
|
||||
<label for="editMode"><?php echo escape($lang["openai_image_edit__mode"]) ?></label><br>
|
||||
<select id="editMode">
|
||||
<option value="edit"><?php echo escape($lang["openai_image_edit__mode_edit"]); ?></option>
|
||||
<option value="variation"><?php echo escape($lang["openai_image_edit__mode_variation"]); ?></option>
|
||||
<option value="generate"><?php echo escape($lang["openai_image_edit__mode_generate"]); ?></option>
|
||||
<option value="white"><?php echo escape($lang["openai_image_edit__mode_white"]); ?></option>
|
||||
<option value="black"><?php echo escape($lang["openai_image_edit__mode_black"]); ?></option>
|
||||
<option value="clone"><?php echo escape($lang["openai_image_edit__mode_clone"]); ?></option>
|
||||
</select>
|
||||
<br><br>
|
||||
<label for="penSize"><?php echo escape($lang["openai_image_edit__pensize"]); ?></label><br>
|
||||
<input type="range" id="penSize" min="10" max="200" value="75">
|
||||
<br><br>
|
||||
<label for="prompt"><?php echo escape($lang["openai_image_edit__prompt"]); ?></label><br>
|
||||
<textarea id="prompt" rows="5" required placeholder="Prompt for regeneration">Complete image as appropriate</textarea>
|
||||
<br>
|
||||
<button id="clearBtn" onclick="window.location.reload();"><?php echo escape($lang["openai_image_edit__reset"]); ?></button>
|
||||
<button id="submitBtn"><?php echo escape($lang["openai_image_edit__generate"]); ?></button>
|
||||
<br><br><br>
|
||||
|
||||
|
||||
<div id="downloadOptions" style="visibility: hidden;">
|
||||
<label for="downloadType"><?php echo escape($lang["openai_image_edit__exportoptions"]); ?></label><br>
|
||||
<select id="downloadType">
|
||||
<option value="image/jpeg">JPEG</option>
|
||||
<option value="image/png">PNG</option>
|
||||
<option value="image/webp">WEBP</option>
|
||||
</select>
|
||||
<br>
|
||||
<select id="downloadAction">
|
||||
<option value="download"><?php echo escape($lang["openai_image_edit__download"]); ?></option>
|
||||
<?php if ($edit_access) { ?><option value="alternative"><?php echo escape($lang["openai_image_edit__alternative"]); ?></option><?php } ?>
|
||||
<?php if (checkperm("c")) { ?><option value="new"><?php echo escape($lang["openai_image_edit__new"]); ?></option><?php } ?>
|
||||
|
||||
</select>
|
||||
<br>
|
||||
<button id="downloadBtn"><?php echo escape($lang["openai_image_edit__export"]); ?></button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
CentralSpaceShowProcessing();
|
||||
submit_url='<?php echo generateURL($baseurl . "/plugins/openai_image_edit/pages/edit.php",[],["ref"=>$ref]); ?>';
|
||||
alternative_url='<?php echo generateURL($baseurl . "/plugins/openai_image_edit/pages/save_alternative.php",[],["ref"=>$ref]); ?>';
|
||||
save_new_url='<?php echo generateURL($baseurl . "/plugins/openai_image_edit/pages/save_new.php",[] ,["ref"=>$ref]); ?>';
|
||||
view_url='<?php echo generateURL($baseurl . "/pages/view.php",[],["ref"=>$ref]); ?>';
|
||||
view_new_url='<?php echo $baseurl ?>/pages/view.php?ref=';
|
||||
csrf_pair={<?php echo generateAjaxToken("openai_image_edit"); ?>};
|
||||
defaultLoadingMessage=<?php echo json_encode($lang["openai_image_edit__preparing_images"]) ?>;
|
||||
</script>
|
||||
<script src="../js/edit.js"></script>
|
||||
<?php
|
||||
include "../../../include/footer.php";
|
||||
|
Reference in New Issue
Block a user