resize obrazkov prilis neproporcionalnych rozmerov
- Bladerik
- Člen | 1
Zdravim mam problem pri uploade obrazkov s prilis neproporcionalnymi
rozmermi, pri uploade obrazku ktory chcem resiznut a ma sirku napr. 5 px a
vysku napr. 5000 px mi vyskoci vynimka
‚Image width and height must be greater than zero‘
ono to vyzera tak ze ked resizujem ten obrazok tak nette dopocita sirku mensiu ako 1 pixel, zatial to riesim odchytavanim exceptionov ale skor by som prijal nieco taketo
<?php
if($obrZmenseny->getWidth() < 1){
$obrZmenseny->resize(1, 60, Image::ENLARGE | Image::STRETCH);
} else if ($obrZmenseny->getHeight() < 1){
$obrZmenseny->resize(80, 1, Image::ENLARGE | Image::STRETCH);
}
?>
ale kedze sa mi vynimka vyhodi na riadku ktory je pred touto podmienkou tak sa to k tomu ani nedostane, konkretne vynimka vyskoci tu na druhom riadku
<?php
if($obrZmenseny->getHeight() > 60){
$obrZmenseny->resize(80, 60);
} else {
$obrZmenseny->resize(80, 60, NImage::ENLARGE);
}
?>
ono je malo pravdepodobne ze mi niekto bude uploadovat obrazok s takymito
rozmermi ale to co programujem by som chcel mat co najuniverzalnejsie :)
este raz opakujem ze pri inych obrazkoch ktore nemaju takyto velky percentualny
rozdiel v sirke a vyske mi vsetko funguje bezproblemovo.
pouzivam Nette Framework 2.0-dev (revision 9e52d77 released on
2010–12–21)
dakujem za rady :)
- Šaman
- Člen | 2666
kravčo napsal(a):
Takže stačí poslať patch na github.
A to můžem i my, prostí neGuru? :)
Bohužel nemám právě teď čas zkoušet GIT (v práci máme SVN) tak
prosím někoho pro koho to bude jen pár kliků, jestli by mohl poslat
tento patch pod čarou:
Původní Image.php
<?php
342: $newWidth = round($srcWidth * $scale);
343: $newHeight = round($srcHeight * $scale);
?>
Upravený Image.php
<?php
342: $newWidth = max(round($srcWidth * $scale), 1);
343: $newHeight = max(round($srcHeight * $scale), 1);
?>
//Edit: Tak to co jsem poslal by opravilo JEN problém s proporciální změnou, ale obecně u všech resizů by bylo lepší upravit až poslední řádek funkce calculateSize() v Image.php
<?php
346: return array((int) $newWidth, (int) $newHeight);
?>
Upravený Image.php
<?php
346: return array( max( (int) $newWidth, 1), max( (int) $newHeight, 1) );
?>
Ale to už mi zase připadá na úkor čitelnosti..
Editoval Šaman (28. 12. 2010 11:46)
- Bernard Williams
- Člen | 207
Nazdárek,
nebylo by jednodušší použít ceil
(zaokrouhlení nahoru)
místo konstrukce max
?
Bernard
- Šaman
- Člen | 2666
To by byl už zásah který něco mění, chtěl jsem patch který opravuje JEN případný chybný stav a navíc na jediném řádku. (Profesionální deformace z doby, kdy jsem upravoval 10 let staré, nezdokumentované prográmky v Pascalu které řídily výrobní stroje ⇒ žádná oprava není dost malá, aby nenasekala další chyby.)
Samozřejmě zaokrouhlení nahoru by problém řešilo taky, jen by bylo více změn.
Editoval Šaman (28. 12. 2010 11:52)
- Šaman
- Člen | 2666
Jj, to znamená. Ale taky to znamená, že mu to nevyhodí výjimku a resizne mu to na nejmenší možný rozměr.
Ceil změní chování už existující funkce (i když minimálně), proto se mi moc nelíbí. Max se bude chovat naprosto stejně jako doposud, dokud jeden rozměr nebude nulový (nebo nedejbože záporný, i když to by nastat nikdy nemělo).
Nechám to na tom, kdo bude patch posílat. Je ale vidět, že i na takové drobnosti může být více názorů, proto jsem předpokládal že právo hrabat se v repozitáři mají jen vybraní jedinci.
- kravčo
- Člen | 721
Šaman napsal(a):
kravčo napsal(a):
Takže stačí poslať patch na github.
A to můžem i my, prostí neGuru? :)
Áno, a neverili by ste, je to veľmi jednoduché. Právo poslať patch má totiž každý. Na patch totiž nepotrebujete prístup do repozitára Nette, posielaný patch je návrhom na zmenu a autor sa môže rozhodnúť či zmenu prijme. (rovnako aj ostatní ľudia s write prístupom do repozitára). Github oplýva nápovedami, takže ani prostí kvázi-neGuruovia, ktorí píšu Nette aplikácie a pracujú s SVN s ním nebudú mať najmenší problém. Stačí len chcieť…
(pozn.: autor príspevku sa za gurua nepovažuje)
Fascinuje ma, ako sa pri nájdení chybky v nette rozthrne vrece s príspevkami typu áno toto určite treba opraviť a (môj obľúbený) +1, zväčša bez riešenia, alebo bez argumentov. Namiesto toho sa zväčša stačí na chvíľu zamyslieť, napísať opravu, k nej jeden-dva testy a poslať pull-request… Alebo diskutovať a navrhnúť riešenie a argumenty preň.
K problému.
Uvažujem na čo je dobrý náhľad obrázku 300×1px (z pôvodného
9000×10px) keď na ňom hovno uvidím. Určite viac platný je náhľad
300×10px (výrez), na ktorom už niečo vidno bude. Mám za to, že vyhodenie
takejto výnimky je trochu blbé, ale osobne mi príde náhľad 300×1px
blbší. Riešením by mohla byť iná výnimkav metóde
Image::resize()
:
if ($newWidth === 0 || $newHeight === 0) {
throw new \InvalidStateException('Image cannot be resized without stretching, width-to-height ratio is out of range.');
}
Bladerik napsal(a):
…
workaround
<?php
use Nette\Image;
//...
$img = Image::fromFile('more-than-wide.jpg'); // 5000x5px
list($w, $h) = Image::calculateSize(
$img->width, $img->height, 80, 80, Image::FIT
);
$w = max(1, $w);
$h = max(1, $w);
$img->resize($w, $h, Image::STRETCH);
$img->send();
- Šaman
- Člen | 2666
kravčo napsal(a):
Mám za to, že vyhodenie takejto výnimky je trochu blbé, ale osobne mi príde náhľad 300×1px blbší.
Průšvih nastane, když máš například možnost uploadovat obrázky k nějakému příspěvku a automaticky generuješ náhledy zmenšením. A pak nějaký chalan uploadne panorama 9000×10px a ty mu vyhodíš pětistovku.. To je podle mě nejhorší.
<blbost>Jestli chceš předjímat co bude uživateli užitečné, tak
budeme muset hlasovat jaký rozměr je minimální a tu
InvalidStateException('Image cannot be resized without stretching..)
budeme vyhazovat pokud některý rozměr klesne pod ten rozměr (navrhuji
5px).</blbost>
Takže jde o to, jak patchnout funkci resize
, aby při
jakémkoliv platném vstupu neházela výjimku, což teď dělá. Ano, lepší
řešení než automatický resize naslepo je výřez. Ve svém projektu jsem to
použil taky tak. Ale to není problém, který řešíme.
<?php
// tvorba náhledu z většího obrázku výřezem na střed
$thumbnailImage = clone $image;
$width = $thumbnailImage->width;
$height = $thumbnailImage->height;
if ( $width/MyImage::WIDTH_THUMBNAIL > $height/MyImage::HEIGHT_THUMBNAIL ) // kdyz je obrazek pomerne delsi nez vyssi
{ // tak upravime vysku a potom orizneme na spravnou sirku
$thumbnailImage->resize(NULL, MyImage::HEIGHT_THUMBNAIL);
}
else
{ // jinak upravime sirku a potom orizneme na spravnou vysku
$thumbnailImage->resize(MyImage::WIDTH_THUMBNAIL, NULL);
}
$thumbnailImage->crop( ( $thumbnailImage->width / 2 - MyImage::WIDTH_THUMBNAIL / 2 ), ( $thumbnailImage->height / 2 - MyImage::HEIGHT_THUMBNAIL / 2 ), MyImage::WIDTH_THUMBNAIL, MyImage::HEIGHT_THUMBNAIL);
?>
Editoval Šaman (28. 12. 2010 19:59)
- kravčo
- Člen | 721
Príklad, keď expert uploadne „panorámu“ 9000×10px je asi taký pravdepodobný ako že ti uploadne chybný typ súboru a výsledok je rovnaký – vyhodená výnimka.
Upísal som sa, chcel som vyhadzovať Nette\ImageException
a
predpokladal som použitie:
try {
$img->resize(80, 80);
} catch (Nette\ImageException $e) {
list($w, $h) = Image::calculateSize(
$img->width, $img->height, 80, 80, Image::FIT
);
$w = max(1, $w);
$h = max(1, $w);
$img->resize($w, $h, Image::STRETCH);
}
Čo nie je veľmi použiteľné v praxi, keďže je to BC break, obaľovanie
každého resize()
do takéhoto try-catch bloku je tiež nafigu a
metóda by to mohla riešiť za nás… Teda štandardne vygenerovať blbý
náhľad s tým, že okrajové podmienky si môže programátor predtým
ošetriť sám a upraviť volanie resize()
podľa potrieb.
- Šaman
- Člen | 2666
Tak jsem si založil účet na GitHUBu a pullnul jsem tu opravu pomocí fce
max.
Akorát k tomu nejsou žádné automatické testy a k ručnímu otestování
se dostanu až po Silvestru. (Dneska hned po práci odjíždím do hor. Tak
pokud mě nezasype lavina, sypejte mi popel na hlavu až o víkendu.)
//Edit: Tak odzkoušeno alespoň použitím v aplikaci. A musím říct, že z obrázku 800×2px se kloudný náhled nevytvoří ani výřezem na střed, dokonce ani když se napřed zvětší a pak ořeže. Prostě kde nic není, ani čert nebere.. Ale obejde se to bez výjimky.
Editoval Šaman (29. 12. 2010 10:53)