Korzystaj z PNG!

10 lutego 2009

PNG to bardzo przydatny format plików graficznych. Powstał jako następca GIF gdy zaczął się cyrk z patentami dotyczącymi kompresji LZW. Główne zalety PNG to kompresja bezstratna, małe rozmiary plików i obsługiwana stopniowa przezroczystość (tzw. kanał alfa).

O PNG pisałem niedawno w kontekście problemów przeglądarki Internet Explorer z tym formatem, wpis Internet Explorer i przezroczyste PNG.

Funkcję przezroczystości posiada również format GIF ale PNG ma tutaj znaczną przewagę. W GIF można jedynie wyznaczyć jeden kolor, który ma być przezroczysty i podczas wyświetlania pliku np. na stronie internetowej odpowiednie piksele po prostu znikają, w ten sposób osiągamy efekt przezroczystości. Natomiast w PNG mamy kanał alfa. Dzięki temu możemy sprawić, że jakiś piksel jest przezroczysty tylko w pewnym procencie (np. półprzezroczysty), nie znika on całkowicie. W ten sposób możemy zrobić np. przejście z w pełni zamalowanego piksela do całkowitej przezroczystości gdzie kolejne piksele stopniowo będą miały coraz większą przezroczystość. Właśnie dlatego w przypadku PNG mówimy o obsłudze stopniowej przezroczystości.

Żeby nie być gołosłownym, chciałbym pokazać możliwości jakie daje nam PNG. Wczoraj przypadkiem trafiłem na ten blog i zainteresował mnie efekt zastosowany do plików graficznych. Zobacz przykład, zwróć szczególną uwagę na narożniki. Prostym sposobem można uzyskać efekt zdjęć wsadzonych do albumu. Jedyny minus to konieczność specjalnego przygotowania zdjęcia za każdym razem gdy chcemy je zamieścić na swojej stronie (efekt jest naniesiony bezpośrednio w pliku graficznym). A może da się łatwiej?

Pewnie, że się da ;) Wystarczy kilka linijek kodu HTML, CSS i jeden pliczek PNG.

Najpierw kod:

HTML:
  1.   <tr>
  2.     <td>
  3.       <div class="img_box">
  4.         <img src="test.png" alt="" />
  5.         <div class="img_top_left"></div>
  6.         <div class="img_top_right"></div>
  7.         <div class="img_bottom_left"></div>
  8.         <div class="img_bottom_right"></div>
  9.       </div>
  10.     </td>
  11.   </tr>
  12. </table>

CSS:
  1. .img_box {
  2.   position: relative;
  3. }
  4.  
  5. .img_box img {
  6.   padding: 5px;
  7.   border: 1px solid #E1E1E1;
  8. }
  9.  
  10. .img_box div {
  11.   position: absolute;
  12.   width: 50px;
  13.   height: 50px;
  14. }
  15.  
  16. .img_box div.img_top_left {
  17.   top: -10px;
  18.   left: -10px;
  19.   background: transparent url(img_effect.png) no-repeat scroll top left;
  20. }
  21.  
  22. .img_box div.img_top_right {
  23.   top: -10px;
  24.   right: -10px;
  25.   background: transparent url(img_effect.png) no-repeat scroll top right;
  26. }
  27.  
  28. .img_box div.img_bottom_left {
  29.   bottom: -10px;
  30.   left: -10px;
  31.   background: transparent url(img_effect.png) no-repeat scroll bottom left;
  32. }
  33.  
  34. .img_box div.img_bottom_right {
  35.   bottom: -10px;
  36.   right: -10px;
  37.   background: transparent url(img_effect.png) no-repeat scroll bottom right;
  38. }

Zacznijmy od div o nadanej klasie img_box. W nim musi się mieścić zarówno zdjęcie jak i inne div'y odpowiedzialne za wyświetlanie wszystkich narożników. Warunkiem koniecznym jest ustawienie dla tego div'a wartości position: relative w CSS. Dlaczego? Ponieważ wewnątrz niego znajdują się div'y pozycjonowane absolutnie, a jak wiemy, zgodnie z zasadami CSS, elementy z position: absolute są pozycjonowane względem tego rodzica, który ma ustawione właśnie position: relative (lub względem elementu body jeżeli żaden rodzic nie ma pozycji relatywnej).

Teraz czas na div'y z narożnikami. Przede wszystkim trzeba im ustawić pozycjonowanie absolutne oraz wysokość i szerokość. Następnie każdy róg z osobna przesuwamy do odpowiedniego narożnika robiąc jeszcze 10 pikseli "zakładki". Przy wykorzystaniu techniki zwanej CSS Sprites (o której pewnie wkrótce napiszę) ustawiamy dla każdego div'a właściwe tło.

Dopełnieniem może być ramka dla zdjęcia, którą ustawiam w CSS w regule .img_box img.

I teraz to czego niektórzy nienawidzą: tabelka :) Dlaczego jest potrzebna? Z prostej przyczyny. Div jest elementem blokowym a wszystkie bloki mają domyślną szerokość 100%. W ten sposób prawe rogi przesuwały się najdalej jak tylko mogły na prawo od naszego zdjęcia. Zależnie od Twoich potrzeb, z lewymi rogami też mogłyby być problemy.

Można dla tego div'a ustawić oczywiście szerokość na sztywno ale przecież nie zawsze zdjęcie do którego chcemy dodać "efekt albumu" będzie takiej samej szerokości. To byłoby zbyt kłopotliwe...

Próbowałem różnych ustawień z display: inline tak aby odpowiedni div jedynie opływał zdjęcie i był takiej samej szerokości co ono. Niestety nic mi z tego nie wychodziło...

Kombinowałem również z display: table ale Internet Explorer tego nie obsługuje :/ Są sposoby żeby jakoś oszukać IE ale najczęściej generuje to kolejne problemy...

Podsumowując: chciałem dobrze ale w końcu mnie szlag trafił i oparłem się na starej dobrej tabelce :) Teraz przynajmniej wiem, że zadziała to tak samo w każdej przeglądarce... Jeżeli kogoś bardzo razi w oczy ta tabelka to nic nie stoi na przeszkodzie żeby to zrobił po swojemu :) Jeżeli znasz na to sposób to opisz wszystko w komentarzu, na pewno komuś się przyda.

Na koniec przezroczysty PNG, którego użyłem w przykładzie. Jak on będzie wyglądał, tak naprawdę zależy od Twojej fantazji. Musisz również dostosować go kolorystycznie jeżeli masz inne tło na stronie niż białe.

A oto efekt jaki w ten sposób uzyskamy (zdjęcie pochodzi ze strony Tomaszowa Mazowieckiego):

Prawda, że ładnie to wygląda? :) Dla mnie bomba ;) Testowałem działanie na IE6, IE7, FF3, Operze, Google Chrome, Safari i Mozilla Suite. Nigdzie nie napotkałem problemów. Nie testowałem w FF2 ale również tam nie spodziewam się błędów.

Mam nadzieję, że na tym przykładzie pokazałem, że warto korzystać z PNG, zwłaszcza tych przezroczystych :) Więcej informacji o PNG znajdziesz tutaj.

PS
Powyższy przykład działania jest obrazkiem bo nie chciałem sobie komplikować życia (dodawać nowych reguł CSS do bloga albo zaśmiecać sobie w jakiś inny sposób kodu) ale screen pochodzi ze strony gdzie efekt uzyskałem za pomocą powyższych kodów HTML i CSS.

Dodaj komentarz

9 odpowiedzi dla tego wpisu

  1. KCh napisał:

    PNG to też mój ulubiony format… jakoś tak wszysło i zostało;)

  2. Mateusz Żeromski napisał:

    Rozwiązanie bardzo nieprofesjonalne, tak towrząc narożniki nie wykorzystamy takiego obrazka nigdzie indziej – sam miales problemy z umieszczeniem js i css we wpisie na blogu.

    Stosowanie ieHack dla tego przypadku jest trochę bez sensu, bo jezeli na stronie wyklorzystujemy obrazki w takim stylu – występuje przerost formy nad treścią – dodatkowy, zbędny kod html,css,js.

    Takie rzeczy powienien przejmować automat, dodawanie ramki, i narożników – np taki jak ja napisałem, zapraszam
    http://blog.zeromski.com.pl/20.....a-obrazku/

  3. MariuszT napisał:

    Nie zgadzam się kompletnie ze wszystkim co napisałeś, zarówno tu jak i na swoim blogu :)

    Właśnie główne założenie było takie aby nie modyfikować obrazka źródłowego. Piszesz, że „tak tworząc narożniki nie wykorzystamy takiego obrazka nigdzie indziej”. Czy czasem coś Ci się nie pomyliło? :D To właśnie Twojego obrazka nigdzie indziej nie wykorzystamy, mój przecież nie jest modyfikowany :) No chyba, że chodzi o to, że nie użyjemy nigdzie indziej obrazka z narożnikami bo są dodawane przez HTML/CSS/JS. Tylko jak często będzie taka potrzeba? Najczęściej taki obrazek z narożnikami nie będzie nigdzie indziej pasował. A jeżeli tak bardzo chcesz mieć te narożniki na obrazku to wystarczy Print Screen na klawiaturze :) Ale o czym my tu gadamy, taka potrzeba wystąpi w 0,00001% przypadków…

    Nie miałem problemu z umieszczeniem JS i CSS tylko mi się nie chciało ;) Bez sensu modyfikować kod strony dla jednego przykładu w artykule… Ale czy Twoim zdaniem naprawdę lepiej jest np. pisać plugin do WordPress’a niż dodać kilka linijek HTML i CSS?

    Jaki przerost formy nad treścią? PNG jest stosowane już powszechnie (na szczęście!), również te przezroczyste. Nie moja wina, że ludzie z Microsoftu dali ciała z obsługą przezroczystych PNG w IE6. Jeżeli chcesz to możesz olać IE6, wtedy żadnych dodatkowych rozwiązań nie potrzebujesz ;) Sam Microsoft oficjalnie namawia do rezygnacji z ich przeglądarki w wersji 6.

    Nie uważam aby modyfikacja zdjęć źródłowych oraz uruchamianie kilkudziesięciu zasobożernych linijek PHP było lepsze niż kilka linijek w CSS i HTML. Ogólna tendencja jest taka aby jak najwięcej spraw załatwiać właśnie w CSS i/lub JavaScript a Ty zrobiłeś zupełnie odwrotnie…

    Używanie GD nie jest złe ale pamiętaj aby wszystko co możesz przerzucać na client side. Przy stu odwiedzinach strony dziennie nie robi to większej różnicy ale już przy kilku tysiącach poczujesz boleśnie tego typu zabawy z grafiką po stronie PHP.

    Podsumowując: niech każdy robi jak chce ale właśnie po to mój wpis o PNG powstał aby radzić sobie najprostszymi, najmniej inwazyjnymi i najmniej zasobożernymi metodami.

    Dlatego nie mogę się z Tobą zgodzić, sam stworzyłeś bardzo nieprofesjonalne rozwiązanie ;)

    PS
    Nie wiem czy udało mi się Ciebie chociaż w najmniejszym stopniu przekonać więc posłużę się przykładem :) Obaj robimy identyczne strony www na zamówienie. Jedyna różnica jest taka, że ja stosuję swój sposób a Ty swój. Pomijam wszystkie inne rzeczy takie jak wydajność itd.

    Strona istnieje rok czasu, pojawiło się na niej tysiąc zdjęć. Przychodzi wtedy do nas właściciel i mówi, że zmienia wygląd swojej witryny i teraz te narożniki nie mogą już być białe tylko szare bo takie jest nowe tło. I co wtedy zrobisz? :D Będziesz przy każdej zmianie koncepcji grafiki dodawał na nowo narożniki do tysięcy obrazków? A jak właściciel w ogóle będzie chciał zrezygnować z tych narożników? Wtedy to tylko sobie strzelić w łeb bo jeżeli nie robiłeś gdzieś kopii obrazków oryginalnych to teraz nie masz plików źródłowych i nic nie zrobisz, nie usuniesz już tych narożników… A ja w swoim rozwiązaniu naniosę te zmiany w kilka minut ;)

  4. Mateusz Żeromski napisał:

    Hej

    Ogólnie mam taki system, (nawet nie system opracowaną procedurkę) że zawsze na serwerze trzymam pliki źródłowe niezmodyfikowane, w duużych rozmiarach, np w katalogu img/, w przypadku gdy do obrazka odwołuję się poprzez img/XXX/img.jpg dzie xxx to liczba – zapytanie jest przesyłane przez htaccess do skryptu który tylko RAZ tworzy grafikę (np zmniejsza, dodaje narożniki, podpisy) i zapisuje w cache – dlatego nie miałbym problemów ze zmianą ozdobników. Następnie odwołując się do obrazka img/xxx/img.jpg – plik jest automatycznie odczytywany z cache z pomięciem php – samo przekierowanie na docelowy plik – również htaccess. Dodatkowo nie powoduje to zasobożerności bo operacja zmiany obrazka jest wykonywana tylko raz. Można tam również utworzyć miniaturkę – co w twoim rozwiązaniu – jest niemożliwe.

    Zgadzam się z Tobą iż logikę należy przenosić na klienta (walidacja formularzy, kalendarze itp itd), ale takiego rozwiązania z narożnikami w życiu bym nie wykorzystał.

    Wyobraź sobie że masz stronę z charakterem, gdzie istotną rolę odgrywają ozdobniki obrazka – ładnie to wygląda i elegancko, ale ktoś chce sobie ściągnąć zdjęcie na pulpit – wtedy dostaje suchy obrazek, a gdyby dostał z narożnikami – to by było profesjonalne.

    Także Twoje argumenty o zasobożerności mojego rozwiązania – obaliłem. A cena 1MB na serwerach jest tak niska, że ten cache nie spowoduje założenia dysku. Zazwyczaj wszystkie rzeczy jakie można zkaszkować – keszuje :) – zapytania sql, obrazki, generowanie stron – zapisuję wszsytko do statycznych plików na serwerze i je wysyłąm oglądającemu (oczywiście są zgzipowane też :) ).

    Także Ty mnie nie przekonałeś, a zastanów się nad moim rozwiązaniem. Jeszcze bym podkreślił – edytując obrazek php’em a nie jak ty robisz css’em daje nam większe możliwości – narożniki, podpisy zdjęcia – modyfikacje, wycinanie itp. A tworząc dobry system generowania i cachowania – nie będzie problemu z wydajnością i zasobożernością.

    Pzdr
    mat :)

  5. Mateusz Żeromski napisał:

    Mariusz – a wyobraż sobie sytuację – razem robimy te zlecenia i klient mówi – do moich wszystkich tysięcy obrazków chcę dodać
    – znak wodny – tu moje rozwiązanie wygrywa
    – chcę zmienić narożniki – niech będzie remis
    – chcę pomniejszyc wszystkie zdjęcia – znow moje *
    – chcę powiększyć wszystkie zdjęcia – znow moje *

    * – wygrywam dlatego iż pliki źródłowe mam w cache o dużych rozmiarach, np 1200/1200 i mogę dowolnie operować docelowymi wymiarami.

  6. MariuszT napisał:

    Wszystko pięknie i cudownie :) Fajnie, że masz cache, fajnie, że trzymasz oryginalne pliki. Ale zapomniałeś o jednej najważniejszej rzeczy przez co w tej dyskusji nie masz racji – ja tego nie potrzebuję i nie o tym jest ten artykuł ! :)

    Czy to jest temat o tym, że próbuję robić miniaturki ze zdjęć za pomocą HTML/CSS ? Czy to jest temat o tym jak staram się dodać znak wodny po client side ? Czy to jest temat w którym próbuję przekonywać, że jakieś zaawansowane operacje na plikach graficznych lepiej robić ręcznie w programach graficznych?

    Nieeeee….

    To jest temat o tym jak w najprostszy i najmniej inwazyjny sposób dodać ładne narożniki do wybranych przez siebie zdjęć :)

    Gdybym musiał zmniejszyć/powiększyć zdjęcie, musiał dodać znak wodny, obrócić fotkę, zmienić jej kolory itp. to użyłbym GD (no dobra, użyłbym ImageMagick ale to akurat w tej chwili nie ma znaczenia, ogólnie użyłbym jakiejś metody server side). Ale ja tego nie potrzebuję…

    Więcej napiszę! Jeżeli będę chciał żeby użytkownicy mogli sobie ściągnąć zdjęcie z narożnikami to również wykorzystam jakąś metodę server side. Ale właśnie w tym cały pic, że ja tego nie chcę! Chcę aby na stronie zdjęcie miało ładne narożniki ale żeby użytkownik, jeżeli zechce sobie to zdjęcie ściągnąć, dostał czysty, oryginalny plik, bez żadnych udziwnień.

    Więc nie przekonuj mnie, że warto uruchamiać całą machinę w postaci PHP/GD i cisnąć serwer żeby dodać cztery malutkie narożniki, które za pół roku mogą zmienić wygląd lub w ogóle zniknąć. Jeżeli ktoś potrzebuje zaawansowanych operacji to niech się bawi w obrabianie plików po stronie serwera ale ja ze swoimi narożnikami nie muszę i nie chcę tego robić.

    Przykro mi ale nie obaliłeś moich argumentów o zasobożerności ;) Nawet jeżeli masz wbudowany system cache (pomijam fakt, że trzeba go było napisać a przecież tu chodzi tylko o dodanie zwykłych, głupiutkich narożników a Ty ludziom każesz babrać się w PHP i .htaccess) to i tak w Twoim rozwiązaniu trzeba uruchomić skrypt PHP, który przetrawi obrazek, doda do niego odpowiednie elementy i zapisze. Czy Ty zdajesz sobie sprawę jak dużo pracy kosztuje to serwer?

    A w moim rozwiązaniu zapisujemy kilka linijek HTML, kilka CSS i jeden malutki obrazek PNG, które po pierwszym wczytaniu są cachowane po stronie użytkownika.

    Które rozwiązanie kosztuje mniej pracy nasz serwer? :)

    Podsumowując: Twoje rozwiązanie jest dobre, ładne i przyjemne tylko zupełnie niepraktyczne i nieprzydatne przy tych konkretnych potrzebach :) Znasz takie powiedzenie: z armatą na muchę? :)

    PS
    Również cachuje co się da aby odciążyć przede wszystkim bazę danych i popieram takie działania. Ale to zupełnie inna bajka i nijak się ma do aktualnego tematu :)

  7. Mateusz Żeromski napisał:

    Wiesz co, i Ty masz rację i ja mam rację – zależy od kąta patrzenia :)

    Zostawmy więc dyskusję na ten temat, bo jedynie możemy zacząć się unosić i poobrażać heeh itp – ja nie zmienie Twojego zdania a Ty mojego :)

    Kiedyś usłyszałem – z nami informatykami jest jak z fryzjerami, bo przychodząc do fryzjera on mówi
    „Kto Pana/Panią tak ściał, co to jest, co za styl?”
    a informatyk
    „Nie no kto to robił, to się do niczego nie nadaje, trzeba od nowa…”

    Najlepszy system informatyczny to taki który działa także nie dyskutujmy już o wyższości czyjegoś rozwiązania bo to już bez sensu :)

  8. MariuszT napisał:

    Oczywiście, że obaj mamy rację :) Tylko nasze rozwiązania, chociaż w tym konkretnym przypadku dają podobny wynik, powinny być stosowane zamiennie, zależnie od głównych założeń.

    Przy moich założeniach (najprostsza, najmniej inwazyjna metoda, która nie zmodyfikuje mi oryginałów) mój sposób jest lepszy. Przy założeniach, że chcemy zmienić nasze pliki i przy okazji dodajemy tam jeszcze napis, znak wodny, zmieniamy wielkość zdjęcia itp. można się pokusić o to aby wszystko załatwić przez PHP.

    Wszystko zależy od tego co potrzebujemy :) Pozdrawiam :)

  9. Bogdan napisał:

    PNG to jest chyba najlepszy format, nie traci na jakości no i zdjęcia nie mają znowu jakiegoś mega rozmiaru. Np. przy screenie 1680×1050 zaoszczędzamy 2mb w stosunku do bmp, rzadko jednak tak wielkie obrazy zapisujemy w PNG, w większości to małe pliki.

Odpowiedz



Podobne wpisy: