2013-04-18 10 views
10

Czy możliwe jest renderowanie skalowanego obrazu w ImageView w JavaFX 2.2 bez stosowania wygładzania? Renderuję obraz o wymiarach 50x50 w obrazie o rozdzielczości 200x200, z funkcją setSmooth (fałsz), więc każdy piksel na obrazie źródłowym powinien być odwzorowany na kwadrat 4x4 na ekranie.JavaFX ImageView bez wygładzania

Jednak wynikowy rendering nadal wygładza piksel źródłowy dla wszystkich 16 docelowych pikseli. Czy ktoś wie, jak to zrobić, bez ręcznego kopiowania każdego piksela na nowy obraz?

+0

Możesz spróbować Canvas, aby uzyskać maksymalną kontrolę. –

+0

Niestety nie sądzę, że można to zrobić na płótnie. To, co naprawdę muszą zrobić, to pozwolić nam tworzyć własne filtry 2D (prawdopodobnie są one nazywane "Efektami" w JavaFX). – ajselvig

+0

Zaktualizowałem swoją odpowiedź, przedstawiając pomysły dotyczące implementacji własnego filtru obrazu. – jewelsea

Odpowiedz

15

W języku JavaFX 2.2 ImageView zawsze będzie wykonywane wygładzanie, niezależnie od wskazania smooth, które poda się do .

(W oparciu o testy z wykorzystaniem oprogramowania Java 7u15 i Windows 7 z kartą graficzną ATI HD4600).

Być może jest to błąd, który powoduje, że ImageView zawsze wygładza Image, ale dokumentacja nie precyzuje dokładnie, co wygładzanie robi lub czego nie robi, więc trudno powiedzieć, jaki jest jego prawdziwy zamiar. Możesz zamieścić odwołanie do tego pytania na openjfx-dev mailing list lub zgłoś problem w numerze JavaFX issue tracker, aby uzyskać bardziej ekspercką opinię od programisty.


Próbowałem kilka różnych metod skalowania obrazka:

  1. skalę w Image constructor.
  2. Skala w ImageView z fitWidth/fitHeight.
  3. Skalowanie przy użyciu właściwości scaleX/scaleY na urządzeniu ImageView.
  4. Skalowanie poprzez próbkowanie Image za pomocą PixelReader i utworzenie nowego obrazu za pomocą PixelWriter.

Uważam, że metody 1 & 4 spowodowało gwałtowny piksele obrazu, jak chcesz za i 2 & 3 spowodowało rozmyte aliasing obrazu.

robot-sampling

Sample code wygenerować powyższym przykładzie.


Aktualizacja z pomysłów na realizację własnych filtr obrazu

JavaFX efekt nie jest taki sam jak stosowany filtr dla funkcji wczytywania obrazu, chociaż efekt filtrowania obraz mógł zostać utworzony. W JavaFX 2.2 publicznie udokumentowany interfejs API wspierający tworzenie niestandardowych efektów, więc tworzenie niestandardowego efektu może okazać się trudne.

Urządzenie zostało ostatnio otwarte w ramach openjfx project, więc można na to spojrzeć, aby sprawdzić, w jaki sposób jest obecnie stosowane filtrowanie.

Możesz także złożyć plik feature request against the JavaFX runtime project, aby "umożliwić nam tworzenie własnych filtrów 2D".

+1

Zawsze dajecie tak imponujące odpowiedzi jewelsea: D –

+1

Tak, dziękuję za szczegółową odpowiedź. Doszedłem do tego samego wniosku i zakończyłem wdrażanie # 4. Sama implementacja jest banalna, ale obawiam się, że jest ona znacznie wolniejsza niż # 2 lub # 3 (chociaż jeszcze jej nie zweryfikowałem). – ajselvig

+2

Minęły dwa lata od tej odpowiedzi. Czy ktoś wie, czy zostało to naprawione w JavaFX? –

1

Wiem, że jest nieco starszy, ale ostatnio potrzebowałem takiego ImageView, a następujący mały hack robi dokładnie to, co chcę na moim komputerze (Windows). Brak gwarancji, że działa wszędzie.

import com.sun.javafx.sg.prism.NGImageView; 
import com.sun.javafx.sg.prism.NGNode; 
import com.sun.prism.Graphics; 
import com.sun.prism.Texture; 
import com.sun.prism.impl.BaseResourceFactory; 

import com.sun.prism.Image; 
import javafx.scene.image.ImageView; 

@SuppressWarnings("restriction") 
public class PixelatedImageView extends ImageView { 
    @Override protected NGNode impl_createPeer() { 
     return new NGImageView() { 
      private Image image; 

      @Override public void setImage(Object img) { 
       super.setImage(img); 
       image = (Image) img; 
      } 

      @Override protected void renderContent(Graphics g) { 
       BaseResourceFactory factory = (BaseResourceFactory) g.getResourceFactory(); 
       Texture tex = factory.getCachedTexture(image, Texture.WrapMode.CLAMP_TO_EDGE); 
       tex.setLinearFiltering(false); 
       tex.unlock(); 
       super.renderContent(g); 
      } 
     }; 
    } 
} 

Podejście polega na tym, że tekstura zostaje ponownie wykorzystana, więc ustawienie filtrowania liniowego pozostaje "lepkie". Dlaczego NGImageView nie można po prostu przekazać "gładkiej" flagi do liniowego ustawienia filtrowania tekstur, jest jednak poza mną.

+0

Wygląda na to, że nie chcą, abyś to zrobił. – Nolan

+0

To działało dla języka Java 8, ale wygląda na to, że funkcje wymienione tutaj zostały zmienione i ustawione na prywatne funkcje w Javie 9. Nie wygląda na to, że można je przesłonić w ten sam sposób bez znaczących zmian w 'ImageView' i' ImageViewHelper' . Ktoś wymyślił, jak obejść nowe ograniczenia w Javie 9? – ddukki

0

Po dodaniu następującego konstruktora do odpowiedzi Martina Sojki można po prostu przekazać obraz javafx do konstruktora. Również pomimo ostrzeżeń o przestarzałych funkcjach jego odpowiedź nadal działa poprawnie (na JDK 1.8_121).

public PixelatedImageView (javafx.scene.image.Image image) { 
    super(image); 
}