mirror of
https://github.com/openvk/openvk
synced 2024-12-22 16:42:32 +03:00
Experiment(Photo): add "quick" image saving method to increase teh upload speedz
если это сработает то я буду ржать :)
This commit is contained in:
parent
8caf57d7b0
commit
65a232b6ef
4 changed files with 123 additions and 30 deletions
|
@ -1,6 +1,8 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Models\Entities;
|
namespace openvk\Web\Models\Entities;
|
||||||
use MessagePack\MessagePack;
|
use MessagePack\MessagePack;
|
||||||
|
use Nette\Utils\ImageException;
|
||||||
|
use Nette\Utils\UnknownImageFileException;
|
||||||
use openvk\Web\Models\Entities\Album;
|
use openvk\Web\Models\Entities\Album;
|
||||||
use openvk\Web\Models\Repositories\Albums;
|
use openvk\Web\Models\Repositories\Albums;
|
||||||
use Chandler\Database\DatabaseConnection as DB;
|
use Chandler\Database\DatabaseConnection as DB;
|
||||||
|
@ -13,48 +15,62 @@ class Photo extends Media
|
||||||
protected $fileExtension = "jpeg";
|
protected $fileExtension = "jpeg";
|
||||||
|
|
||||||
const ALLOWED_SIDE_MULTIPLIER = 7;
|
const ALLOWED_SIDE_MULTIPLIER = 7;
|
||||||
|
|
||||||
private function resizeImage(string $filename, string $outputDir, \SimpleXMLElement $size): array
|
/**
|
||||||
|
* @throws \ImagickException
|
||||||
|
* @throws ImageException
|
||||||
|
* @throws UnknownImageFileException
|
||||||
|
*/
|
||||||
|
private function resizeImage(\Imagick $image, string $outputDir, \SimpleXMLElement $size): array
|
||||||
{
|
{
|
||||||
$res = [false];
|
$res = [false];
|
||||||
$image = Image::fromFile($filename);
|
|
||||||
$requiresProportion = ((string) $size["requireProp"]) != "none";
|
$requiresProportion = ((string) $size["requireProp"]) != "none";
|
||||||
if($requiresProportion) {
|
if($requiresProportion) {
|
||||||
$props = explode(":", (string) $size["requireProp"]);
|
$props = explode(":", (string) $size["requireProp"]);
|
||||||
$px = (int) $props[0];
|
$px = (int) $props[0];
|
||||||
$py = (int) $props[1];
|
$py = (int) $props[1];
|
||||||
if(($image->getWidth() / $image->getHeight()) > ($px / $py)) {
|
if(($image->getImageWidth() / $image->getImageHeight()) > ($px / $py)) {
|
||||||
# For some weird reason using resize with EXACT flag causes system to consume an unholy amount of RAM
|
$height = ceil(($px * $image->getImageWidth()) / $py);
|
||||||
$image->crop(0, 0, "100%", (int) ceil(($px * $image->getWidth()) / $py));
|
$image->cropImage($image->getImageWidth(), $height, 0, 0);
|
||||||
$res[0] = true;
|
$res[0] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($size["maxSize"])) {
|
if(isset($size["maxSize"])) {
|
||||||
$maxSize = (int) $size["maxSize"];
|
$maxSize = (int) $size["maxSize"];
|
||||||
$image->resize($maxSize, $maxSize, Image::SHRINK_ONLY | Image::FIT);
|
$sizes = Image::calculateSize($image->getImageWidth(), $image->getImageHeight(), $maxSize, $maxSize, Image::SHRINK_ONLY | Image::FIT);
|
||||||
|
$image->resizeImage($sizes[0], $sizes[1], \Imagick::FILTER_POINT, 1);
|
||||||
} else if(isset($size["maxResolution"])) {
|
} else if(isset($size["maxResolution"])) {
|
||||||
$resolution = explode("x", (string) $size["maxResolution"]);
|
$resolution = explode("x", (string) $size["maxResolution"]);
|
||||||
$image->resize((int) $resolution[0], (int) $resolution[1], Image::SHRINK_ONLY | Image::FIT);
|
$sizes = Image::calculateSize(
|
||||||
|
$image->getImageWidth(), $image->getImageHeight(), (int) $resolution[0], (int) $resolution[1], Image::SHRINK_ONLY | Image::FIT
|
||||||
|
);
|
||||||
|
$image->resizeImage($sizes[0], $sizes[1], \Imagick::FILTER_POINT, 1);
|
||||||
} else {
|
} else {
|
||||||
throw new \RuntimeException("Malformed size description: " . (string) $size["id"]);
|
throw new \RuntimeException("Malformed size description: " . (string) $size["id"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$res[1] = $image->getWidth();
|
$res[1] = $image->getImageWidth();
|
||||||
$res[2] = $image->getHeight();
|
$res[2] = $image->getImageHeight();
|
||||||
if($res[1] <= 300 || $res[2] <= 300)
|
if($res[1] <= 300 || $res[2] <= 300)
|
||||||
$image->save("$outputDir/" . (string) $size["id"] . ".gif");
|
$image->writeImage("$outputDir/$size[id].gif");
|
||||||
else
|
else
|
||||||
$image->save("$outputDir/" . (string) $size["id"] . ".jpeg");
|
$image->writeImage("$outputDir/$size[id].jpeg");
|
||||||
|
|
||||||
imagedestroy($image->getImageResource());
|
$res[3] = true;
|
||||||
|
$image->destroy();
|
||||||
unset($image);
|
unset($image);
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function saveImageResizedCopies(string $filename, string $hash): void
|
private function saveImageResizedCopies(?\Imagick $image, string $filename, string $hash): void
|
||||||
{
|
{
|
||||||
|
if(!$image) {
|
||||||
|
$image = new \Imagick;
|
||||||
|
$image->readImage($filename);
|
||||||
|
}
|
||||||
|
|
||||||
$dir = dirname($this->pathFromHash($hash));
|
$dir = dirname($this->pathFromHash($hash));
|
||||||
$dir = "$dir/$hash" . "_cropped";
|
$dir = "$dir/$hash" . "_cropped";
|
||||||
if(!is_dir($dir)) {
|
if(!is_dir($dir)) {
|
||||||
|
@ -67,8 +83,13 @@ class Photo extends Media
|
||||||
throw new \RuntimeException("Could not load photosizes.xml!");
|
throw new \RuntimeException("Could not load photosizes.xml!");
|
||||||
|
|
||||||
$sizesMeta = [];
|
$sizesMeta = [];
|
||||||
foreach($sizes->Size as $size)
|
if(OPENVK_ROOT_CONF["openvk"]["preferences"]["photos"]["photoSaving"] === "quick") {
|
||||||
$sizesMeta[(string) $size["id"]] = $this->resizeImage($filename, $dir, $size);
|
foreach($sizes->Size as $size)
|
||||||
|
$sizesMeta[(string)$size["id"]] = [false, false, false, false];
|
||||||
|
} else {
|
||||||
|
foreach($sizes->Size as $size)
|
||||||
|
$sizesMeta[(string)$size["id"]] = $this->resizeImage(clone $image, $dir, $size);
|
||||||
|
}
|
||||||
|
|
||||||
$sizesMeta = MessagePack::pack($sizesMeta);
|
$sizesMeta = MessagePack::pack($sizesMeta);
|
||||||
$this->stateChanges("sizes", $sizesMeta);
|
$this->stateChanges("sizes", $sizesMeta);
|
||||||
|
@ -76,13 +97,19 @@ class Photo extends Media
|
||||||
|
|
||||||
protected function saveFile(string $filename, string $hash): bool
|
protected function saveFile(string $filename, string $hash): bool
|
||||||
{
|
{
|
||||||
$image = Image::fromFile($filename);
|
$image = new \Imagick;
|
||||||
if(($image->height >= ($image->width * Photo::ALLOWED_SIDE_MULTIPLIER)) || ($image->width >= ($image->height * Photo::ALLOWED_SIDE_MULTIPLIER)))
|
$image->readImage($filename);
|
||||||
|
$h = $image->getImageHeight();
|
||||||
|
$w = $image->getImageWidth();
|
||||||
|
if(($h >= ($w * Photo::ALLOWED_SIDE_MULTIPLIER)) || ($w >= ($h * Photo::ALLOWED_SIDE_MULTIPLIER)))
|
||||||
throw new ISE("Invalid layout: image is too wide/short");
|
throw new ISE("Invalid layout: image is too wide/short");
|
||||||
|
|
||||||
$image->resize(8192, 4320, Image::SHRINK_ONLY | Image::FIT);
|
$sizes = Image::calculateSize(
|
||||||
$image->save($this->pathFromHash($hash), 92, Image::JPEG);
|
$image->getImageWidth(), $image->getImageHeight(), 8192, 4320, Image::SHRINK_ONLY | Image::FIT
|
||||||
$this->saveImageResizedCopies($filename, $hash);
|
);
|
||||||
|
$image->resizeImage($sizes[0], $sizes[1], \Imagick::FILTER_POINT, 1);
|
||||||
|
$image->writeImage($this->pathFromHash($hash));
|
||||||
|
$this->saveImageResizedCopies($image, $filename, $hash);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -114,8 +141,8 @@ class Photo extends Media
|
||||||
$sizes = $this->getRecord()->sizes;
|
$sizes = $this->getRecord()->sizes;
|
||||||
if(!$sizes || $forceUpdate) {
|
if(!$sizes || $forceUpdate) {
|
||||||
if($forceUpdate || $upgrade || OPENVK_ROOT_CONF["openvk"]["preferences"]["photos"]["upgradeStructure"]) {
|
if($forceUpdate || $upgrade || OPENVK_ROOT_CONF["openvk"]["preferences"]["photos"]["upgradeStructure"]) {
|
||||||
$hash = $this->getRecord()->hash;
|
$hash = $this->getRecord()->hash;
|
||||||
$this->saveImageResizedCopies($this->pathFromHash($hash), $hash);
|
$this->saveImageResizedCopies(NULL, $this->pathFromHash($hash), $hash);
|
||||||
$this->save();
|
$this->save();
|
||||||
|
|
||||||
return $this->getSizes();
|
return $this->getSizes();
|
||||||
|
@ -127,6 +154,16 @@ class Photo extends Media
|
||||||
$res = [];
|
$res = [];
|
||||||
$sizes = MessagePack::unpack($sizes);
|
$sizes = MessagePack::unpack($sizes);
|
||||||
foreach($sizes as $id => $meta) {
|
foreach($sizes as $id => $meta) {
|
||||||
|
if(isset($meta[3]) && !$meta[3]) {
|
||||||
|
$res[$id] = (object) [
|
||||||
|
"url" => "/photos/thumbnails/" . $this->getId() . "_$id.jpeg",
|
||||||
|
"width" => NULL,
|
||||||
|
"height" => NULL,
|
||||||
|
"crop" => NULL
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$url = $this->getURL();
|
$url = $this->getURL();
|
||||||
$url = str_replace(".$this->fileExtension", "_cropped/$id.", $url);
|
$url = str_replace(".$this->fileExtension", "_cropped/$id.", $url);
|
||||||
$url .= ($meta[1] <= 300 || $meta[2] <= 300) ? "gif" : "jpeg";
|
$url .= ($meta[1] <= 300 || $meta[2] <= 300) ? "gif" : "jpeg";
|
||||||
|
@ -149,6 +186,47 @@ class Photo extends Media
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function forceSize(string $sizeName): bool
|
||||||
|
{
|
||||||
|
$hash = $this->getRecord()->hash;
|
||||||
|
$sizes = MessagePack::unpack($this->getRecord()->sizes);
|
||||||
|
$size = $sizes[$sizeName] ?? false;
|
||||||
|
if(!$size)
|
||||||
|
return $size;
|
||||||
|
|
||||||
|
if(!isset($size[3]) || $size[3] === true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
$path = $this->pathFromHash($hash);
|
||||||
|
$dir = dirname($this->pathFromHash($hash));
|
||||||
|
$dir = "$dir/$hash" . "_cropped";
|
||||||
|
if(!is_dir($dir)) {
|
||||||
|
@unlink($dir);
|
||||||
|
mkdir($dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sizeMetas = simplexml_load_file(OPENVK_ROOT . "/data/photosizes.xml");
|
||||||
|
if(!$sizeMetas)
|
||||||
|
throw new \RuntimeException("Could not load photosizes.xml!");
|
||||||
|
|
||||||
|
$sizeInfo = NULL;
|
||||||
|
foreach($sizeMetas->Size as $size)
|
||||||
|
if($size["id"] == $sizeName)
|
||||||
|
$sizeInfo = $size;
|
||||||
|
|
||||||
|
if(!$sizeInfo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$pic = new \Imagick;
|
||||||
|
$pic->readImage($path);
|
||||||
|
$sizes[$sizeName] = $this->resizeImage($pic, $dir, $sizeInfo);
|
||||||
|
|
||||||
|
$this->stateChanges("sizes", MessagePack::pack($sizes));
|
||||||
|
$this->save();
|
||||||
|
|
||||||
|
return $sizes[$sizeName][3];
|
||||||
|
}
|
||||||
|
|
||||||
function getVkApiSizes(): ?array
|
function getVkApiSizes(): ?array
|
||||||
{
|
{
|
||||||
|
|
|
@ -185,6 +185,18 @@ final class PhotosPresenter extends OpenVKPresenter
|
||||||
$this->renderPhoto($photo->getOwner(true)->getId(), $photo->getVirtualId());
|
$this->renderPhoto($photo->getOwner(true)->getId(), $photo->getVirtualId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderThumbnail($id, $size): void
|
||||||
|
{
|
||||||
|
$photo = $this->photos->get($id);
|
||||||
|
if(!$photo || $photo->isDeleted())
|
||||||
|
$this->notFound();
|
||||||
|
|
||||||
|
if(!$photo->forceSize($size))
|
||||||
|
chandler_http_panic(588, "Gone", "This thumbnail cannot be generated due to server misconfiguration");
|
||||||
|
|
||||||
|
$this->redirect($photo->getURLBySizeId($size), 8);
|
||||||
|
}
|
||||||
|
|
||||||
function renderEditPhoto(int $ownerId, int $photoId): void
|
function renderEditPhoto(int $ownerId, int $photoId): void
|
||||||
{
|
{
|
||||||
$this->assertUserLoggedIn();
|
$this->assertUserLoggedIn();
|
||||||
|
|
|
@ -163,6 +163,8 @@ routes:
|
||||||
handler: "Photos->uploadPhoto"
|
handler: "Photos->uploadPhoto"
|
||||||
- url: "/photo{num}_{num}"
|
- url: "/photo{num}_{num}"
|
||||||
handler: "Photos->photo"
|
handler: "Photos->photo"
|
||||||
|
- url: "/photos/thumbnails/{num}_{text}.jpeg"
|
||||||
|
handler: "Photos->thumbnail"
|
||||||
- url: "/photos/{text}"
|
- url: "/photos/{text}"
|
||||||
handler: "Photos->absolutePhoto"
|
handler: "Photos->absolutePhoto"
|
||||||
- url: "/photo{num}_{num}/edit"
|
- url: "/photo{num}_{num}/edit"
|
||||||
|
|
|
@ -18,7 +18,8 @@ openvk:
|
||||||
forbiddenNames:
|
forbiddenNames:
|
||||||
- "index.php"
|
- "index.php"
|
||||||
photos:
|
photos:
|
||||||
upgradeStructure: true
|
upgradeStructure: false
|
||||||
|
photoSaving: "quick"
|
||||||
apps:
|
apps:
|
||||||
withdrawTax: 8
|
withdrawTax: 8
|
||||||
security:
|
security:
|
||||||
|
|
Loading…
Reference in a new issue