Kompresja obrazu w javie

Jest wiele metod kompresji, wiele różnych algorytmów, które to wykonują. Oczywiście, można samemu napisać kompresję obrazu ale czy warto, skoro można skorzystać z gotowych rozwiązań. W javie z pomocą idą nam klasy z pakietu javax.imageio i przykładowy kod może wyglądać następująco.

private void compress(BufferedImage image, File file, float compressionLevel) {
   ImageWriter writer = null;
   Iterator iterator = ImageIO.getImageWritersByFormatName("jpg");
   if (iterator.hasNext()) {
      writer = (ImageWriter) iterator.next();
   }
   ImageOutputStream ios = null;

   ios = ImageIO.createImageOutputStream(file);
   writer.setOutput(ios);

   ImageWriteParam imageWriteParam = writer.getDefaultWriteParam();
   imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
   imageWriteParam.setCompressionQuality(compressionLevel);

   writer.write(null, new IIOImage(image, null, null), imageWriteParam);

   ios.flush();
   writer.dispose();
   ios.close();

} 

Ta metoda za parametry przyjmuje:

  • obraz, kt6ry będzie kompresowany
  • plik, do którego będzie zapisany skompresowany wynik
  • oraz stopień kompresji. Współczynnik ten przyjmuje wartości od 0.0 do 1.0. Im niższy tym rozmiar pliku jest mniejszy ale jednocześnie gorsza jakość.

A kod początkowo pobiera writera dla odpowiedniego typu – jpg i ustawia odpowiedni outputStream, ustawia jego parametry i dokonuje kompresji. Oczywiście nie należy zapominać o obsłudze wyjątków, które tutaj są pominięte.

Iterowanie między przedziałem czasu

Dosyć często w aplikacjach wykorzystujemy czas aby ograniczyć dane pomiędzy czasem początkowym i końcowym. W takich sytuacjach czas ma znaczenie drugorzędne. Jednak czasem zdarza się, że konkretna data ma znaczenie pierwszorzędne a to co jest przypisane do czasu jest dodatkiem. W takich sytuacjach, trzeba nieraz wykonywać operacje na kolekcjach dat.

Przy zakresie dat, gdzie zazwyczaj mamy datę początku i końca, przechodzenie po kolejnych elementach trochę się różni od zwykłych iteracji. I co mnie zdziwiło ale nie udało mi się znaleźć gotowej klasy, metody która to wykonuje. Jeśli istnieje to byłbym wdzięczny za informacje.

Ale samodzielne napisanie takiego iteratora nie jest wielkim problemem. Poniższy przykład wykorzystuje bibliotekę joda-time ale nic nie stoi na przeszkodzie aby użyć dowolnych klas odpowiadających za operacje na czasie.

import org.joda.time.*;
import java.util.*;

public class LocalDateRange implements Iterable<LocalDate>
{
    private final LocalDate start;
    private final LocalDate end;

    public LocalDateRange(LocalDate start,
                          LocalDate end)
    {
        this.start = start;
        this.end = end;
    }

    public Iterator<LocalDate> iterator()
    {
        return new LocalDateRangeIterator(start, end);
    }

    private static class LocalDateRangeIterator implements Iterator<LocalDate>
    {
        private LocalDate current;
        private final LocalDate end;

        private LocalDateRangeIterator(LocalDate start,
                                       LocalDate end)
        {
            this.current = start;
            this.end = end;
        }

        public boolean hasNext()
        {
            return current != null;
        }

        public LocalDate next()
        {
            if (current == null)
            {
                throw new NoSuchElementException();
            }
            LocalDate ret = current;
            current = current.plusDays(1);
            if (current.compareTo(end) > 0)
            {
                current = null;
            }
            return ret;
        }

        public void remove()
        {
            throw new UnsupportedOperationException();
        }
    }
}

W powyższym kodzie nie ma żadnej magii, zaimplementowanie interejsów Iterable oraz Iterator. Kod pochodzi z tej odpowiedzi.

Konfiguracja timezone dla JVM

Krótki post ku pamięci, bo chwilę musiałem poszukać jak ustawić odpowiedni timezone dla maszyny wirtualnej javy. A dokładniej mówiąc dla uruchomionego jbossa. W run.conf do parametrów JAVA_OPTS należy dodać parametr:

-Duser.timezone=Europe/Warsaw

Gdzie Europe/Warsaw zależy od strefy czasowej jaka będzie dla nas poprawna.

Walidacja schematu XSD

Było już tutaj o parsowaniu xml o tworzeniu wizualizacja xml poprzez transformatę xsl ale po co nam to wszystko jeśli nie posiadamy poprawnego xml. Jeśli jest on niezgodny ze schemą xsd. Oczywiście istnieje wiele walidatorów online ale nie zawsze mamy do nich dostęp. Jednym z rozwiązań jest napisanie własnego walidatora. Przy wykorzystaniu javovego api dotyczącego walidacji, jest to prostsze niż się wydaje na pierwszy rzut oka.

import java.io.*;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import org.xml.sax.SAXException;

public class MyValidator {

    public static void main(String[] args) throws SAXException, IOException {

        // 1
        SchemaFactory factory =
            SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

        // 2
        File schemaLocation = new File("/path/to/my/schema.xsd");
        Schema schema = factory.newSchema(schemaLocation);

        // 3
        Validator validator = schema.newValidator();

        // 4
        Source source = new StreamSource(args[0]);

        // 5
        try {
            validator.validate(source);
            System.out.println(args[0] + " is valid.");
        }
        catch (SAXException ex) {
            System.out.println(args[0] + " is not valid because ");
            System.out.println(ex.getMessage());
        }

    }

}

Mniej niż 10 linijek głównego kodu robi wrażenie ale co tu się dzieje kolejno.

  1. Utworzenie fabryki dla konkretnej schemy, domyślnie dostarczone są:
  2. Załadowanie konkretnej schemy xsd i jej kompilacja.
  3. Utworzenie walidatora ze skompilowanej schemy.
  4. Załadowanie xml, który ma zostać sprawdzony.
  5. Przeprowadzenie walidacji. Jeśli xml jest niezgodny ze schema, to zostanie rzucony wyjątek gdzie będzie można się dowiedzieć dlaczego plik jest nie poprawny.

Oparte na tym wpisie

Integracja javy i groovy oraz wstęp do metaprogramowania

Po raz kolejny podwójna dawka wiedzy na podstawie książki Programming Groovy: Dynamic Productivity for the Java Developer. Na początek integracja kodu groovy z kodem java. Tak jak przypuszczałem podczas czytania powyższej książki sprawa jest prosta.

Są 2 opcje uruchomienia kodu groovy:
1.Przez polecenie groovy (automatyczne kompilowanie kodu w pamięci i wykonanie go).
2.Kompilacja przez groovyc i uruchomienie przez polecenie java (należy pamiętać o dodaniu biblioteki groovy do classpatha).

Zazwyczaj skrypty groovy nie są w żadnym pakiecie.

Nie ma różnicy między skompilowanym kodem groovy a java. Użycie klas groovy nie różni się niczym od użycia klas javowych. Jeśli klasy są skompilowane lub w jarze to ich użycie jest normalne (tak jak w javie).

Jeśli kod groovy jest skompilowany lub jarem od razu zadziała z kodem javowym. Jeśli to jest źródło należy użyć groovyc. Javac rozpoznaje wszystkie klasy od których zależy dana klasa i je kompiluje, ale nie rozpoznaje plików z rozszerzeniem groovy. Groovyc to potrafi i dla każdego pliku groovy potrafi skompilować pliki java, należy używać z flagą -j. (joint compilation – kompilacja łączona).

Jeśli wywoływany jest skrypt groovy w klasie groovy to należy użyć:

shell = new GroovyShell()
shell.evaluate(new File('Script1.groovy' ))

lub wersja skrócona

evaluate(new File('Script1.groovy' ))

Wywołanie skryptu groovy z poziomu javy odbywa się na podstawie JSR 223. Inne języki bardziej to wspierają niż groovy z powodu joint compilation, np:

import javax.script.*;
public class CallingScript{
  public static void main(String[] args) {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("groovy" );
    System.out.println("Calling script from Java" );
    try{
      engine.eval("println 'Hello from Groovy'" );
    }
    catch(ScriptException ex){
      System.out.println(ex);
    }
  }
}

Metaprogramowanie

Aby w pełni poznać plusy metaprogramowania w groovy należy zrozumieć obiekty w groovy i manipulowanie na metodach.
Obiekty groovy są co najmniej jak obiekty java ale posiadają więcej funkcji. Obiekty groovy mają bardziej dynamiczne zachowanie niż obiekty java, wywoływanie i operacje na metodach odbywają się w inny sposób niż w obiektach java.

W aplikacjach groovy pracuje się na 3 rodzajach obiektów:
-POJO – klasy javove
-POGO – klasy napisane w groovy rozszerzające java.lang.Object i implementujące groovy.lang.GroovyObject
-interceptory groovy – rozszerzające GroovyInterceptable

Dzięki metodom invokeMethod( ), getProperty( ), and setProperty( ) groovy jest dynamiczny.

Wszystkie interceptory i metody zdefiniowane w MetaClass klasy są ważniejsze niż oryginalne metody w POJO.
hasProperty() sprawdza czy istnieje właściwość.
respondsTo() sprawdza czy istnieje metoda.

Można wywołać metodę bez znania jej nazwy w trakcie pisani(dynamizm):

str = "hello"
methodName = 'toUpperCase'
// Name may come from an input instead of being hard coded
methodOfInterest = str.metaClass.getMetaMethod(methodName)
println methodOfInterest.invoke(str)

Dynamiczne wywołanie właściwości odbywa się w następujący sposób

obj[property]

lub

obj."$usrRequestedProperty"

a metody

obj."$usrRequestedMethod" ()

lub

obj.invokeMethod(usrRequestedMethod, null)

gdzie null to lista argumentów.

Usuwanie komunikatów systemowych

W jsf istnieje prosty sposób implementacji komunikatów w systemie. Czasami się zdarza, że pewna metoda tworzy w swoim ciele komunikat dla użytkownika a w innym miejscu wywołanie tej metody nie powinno wyświetlać żadnej informacji. Utworzenie takiej samej metody, tylko że bez komunikatu jest złamaniem zasady DRY , a znowu dodanie warunków, może doprowadzić do nadmiernej komplikacji.

Prostym rozwiązaniem jest zastosowanie poniższego kodu:

FacesContext context = FacesContext.getCurrentInstance();
   Iterator<String> clients = context.getClientIdsWithMessages();
   while (clients.hasNext()) {
     String clientId = clients.next();
     Iterator<FacesMessage> messages = context.getMessages(clientId);

     while (messages.hasNext()) {
        messages.next();
        messages.remove();
     }
   }

Gdzie są pobierane message a następnie podczas iteracji można je usunąć.

Kolorowanie składni dzięki tej stronie

HttpServletResponse and file name

It’s my first note in english. I think that their content could be better in english than in polish. So, forgive me any mistakes.

Sometimes in web application we create, we need to give download file functionality. Using HttpServletRespone is simple, maybe I’ll write about it soon. But I have problem with setting a file name. And it also was very easy. The solution of this problem is:

response.setHeader("Content-Disposition", "attachment; filename="+ fileName);

%d blogerów lubi to: