Innholdsoversikt for programutvikling
ImageIcon
-bildeImage
-bildeJava har omfattende muligheter for behandling av bilder. I dette notatet blir bare det mest grunnleggende omtalt.
Et bilde som vises på dataskjermen er bygget opp av et stort antall små bildeelementer.
Et slikt bildeelement kalles en piksel, på engelsk pixel, som er forkortelse
for picture element. På skjermen vil en slik piksel være et lite kvadrat, så lite at vi
ikke kan se det med det blotte øye. Hver slik piksel har en bestemt farge og en bestemt lysstyrke.
Bildefiler inneholder opplysninger om farge og lysstyrke for de enkelte pikslene som bildet består av.
Dette kan bli store datamengder og dermed resultere i store filer. For å redusere filstørrelsen
blir det som regel brukt forskjellige komprimeringsteknikker. Avhengig av hvilken komprimeringsteknikk
som er brukt, får vi da forskjellige typer bildefiler. Den vanligste typen for fotografier er
den som har bildefiler med filnavn som slutter på .jpg
eller .jpeg
.
Det er en komprimeringsteknikk som gir kvalitetsforringelse i forhold til originalbildet som
blir komprimert. Hensikten er at dette skal skje på en måte som det menneskelige øyet ikke kan
oppdage. Men dersom vi foretar en eller annen manipulering av et jpg-bilde og lagrer det nye bildet,
er det ikke mulig ut fra den nye fila å få tilbake kvaliteten i originalbildet, så sørg for å
ta vare på originalbildene.
En annen nettstandard for bilder er det som kalles gif-bilder. Bildefiler for slike har
filnavn som slutter med .gif
. Gif-bilder tillater høyst 256 forskjellige farger, mens
jpg-bilder tillater inntil 16,7 millioner. Til gjengjeld gir gif-bilder komprimering uten kvalietetsforringelse.
Gif-formatet egner seg for logoer, strektegninger og ikoner. En annen standard som har
samme egenskaper som gif, er png-standarden. Den ble utviklet som et patentfritt alternativ til
gif-formatet, men det representerer også noen forbedringer på den måten at filstørrelsen blir
5 til 25 prosent mindre enn for et tilsvarende gif-bilde. Java støtter alle de tre nevnte
filformatene.
I java-sammenheng kan et bilde enten være et
ImageIcon
-objekt eller et
Image
-objekt. Egentlig
bruker et ImageIcon
-objekt et Image
-objekt til å
lagre sine bildedata i.
Et ImageIcon
-objekt er et bilde av fast størrelse. Det blir
vanligvis oppfattet som et lite bilde, siden det er slike som brukes som
dekorasjon på for eksempel knapper. Det er imidlertid ingen begrensning på
størrelsen.
Det er litt forskjell på å opprette et ImageIcon
-bilde
avhengig av om det skjer i en applikasjon eller i en applet. I en applikasjon
blir det anbefalt å gjøre det på denne måten (uttrykt i pseudo-kode),
i tilfelle bildefilene tilhører applikasjonen:
ImageIcon bilde = null; java.net.URL kilde = Klasse.class.getResource( < filnavn eller filsti > ); if ( kilde != null ) bilde = new ImageIcon( kilde ); else < passende feilmelding >
Det som ovenfor er kalt Klasse
skal være navn på den klasse
som instruksjonene står i. Det er mulig å opprette et bilde direkte ved å
bruke filnavnet for bildefila som konstruktørparameter. Men ved å gjøre det
som vist ovenfor får man først sjekket om bildefila virkelig er tilgjengelig,
og får mulighet for å gi passende feilmelding dersom det ikke skulle være tilfelle.
ImageIcon
-bildeEt ImageIcon
-bilde har evne til å tegne seg selv ved bruk
av metoden paintIcon
:
bilde.paintIcon(tegneflate, grafikkontekst, x, y);
Tegneflata vil vanligvis være et panel som ikke skal ha andre oppgaver enn
nettopp å vise vedkommende bilde. Det som er kalt grafikkontekst
er den såkalte grafikk-konteksten til tegneflata, det vil si det
Graphics
-objekt som er knyttet til tegneflata og som blant annet
er parameter i tegneflatas paint
- eller paintComponent
-metode.
Parametrene x
og y
angir koordinatene til bildets
øverste venstre hjørne relativt til tegneflata.
Programmet Ikontest.java
som er gjengitt nedenfor tegner et bilde på et JPanel
i et
JFrame
-vindu. Bildefila
Ipeint01.jpg forutsettes å ligge i en
underkatalog bildefiler
under katalogen som inneholder
klassefilene til programmet. Tegnepanelet blir gitt samme størrelse som bildet.
Dimensjonene til dette hentes ut ved bruk av metodene
getIconWidth
og getIconHeight
.
1 import java.awt.*; 2 import javax.swing.*; 3 import java.net.URL; 4 5 //Viser et bilde i form av et ImageIcon i et JFrame-vindu. 6 class Bildepanel extends JPanel 7 { 8 private ImageIcon ikon; 9 10 public Bildepanel() 11 { 12 URL kilde = Bildepanel.class.getResource("bildefiler/Ipeint01.jpg"); 13 if (kilde != null) 14 { 15 ikon = new ImageIcon(kilde); 16 } 17 else 18 { 19 ikon = null; 20 } 21 } 22 23 public void paintComponent(Graphics g) 24 { 25 super.paintComponent(g); 26 if (ikon != null) 27 { 28 ikon.paintIcon(this, g, 0, 0); 29 } 30 else 31 { 32 g.drawString("Fant ikke bildet!", 10, 50); 33 } 34 } 35 36 //Setter panelstørrelse lik bildets størrelse. 37 public Dimension getPreferredSize() 38 { 39 if (ikon != null) 40 { 41 return new Dimension(ikon.getIconWidth(), ikon.getIconHeight()); 42 } 43 else 44 { 45 return new Dimension(200, 100); 46 } 47 } 48 } 49 50 class Bildevindu extends JFrame 51 { 52 public Bildevindu() 53 { 54 setTitle("Ikontest"); 55 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 56 Bildepanel bilde = new Bildepanel(); 57 getContentPane().add(bilde, BorderLayout.CENTER); 58 pack(); 59 } 60 } 61 62 public class Ikontest 63 { 64 public static void main(String[] args) 65 { 66 EventQueue.invokeLater(new Runnable() 67 { 68 public void run() 69 { 70 JFrame vindu = new Bildevindu(); 71 vindu.setVisible(true); 72 } 73 }); 74 } 75 }
Skalering kan vi få til ved å hente ut ImageIcon
-objektets
Image
-objekt ved instruksjonen
Image imagebilde = bilde.getImage();
og tegne Image
-bildet skalert, se nedenfor.
Image
-bildeImage
-bilder har ingen egen tegnemetode. Isteden må vi
bruke Graphics
-klassens
drawImage
-metode for å tegne
dem. Denne finnes i flere versjoner. De to mest aktuelle å bruke er den for å
tegne bildet i den størrelsen
det har, og den for å tegne bildet i skalert størrelse. Bredde og høyde for
det skalerte bildet angis da som ekstra parametre. Signaturene for disse to
versjonene av tegnemetoden er som følger:
boolean drawImage(Image bilde, int x, int y, ImageObserver sted) boolean drawImage(Image bilde, int x, int y, int bredde, int høyde, ImageObserver sted)
Parametrene x
og y
angir i begge versjoner
koordinatene for bildets øverste venstre hjørne relativt til tegneflata.
Siste parameter skal vanligvis være en referanse til den komponent som bildet
skal vises på. Som regel vil kallet på drawImage
bli foretatt
inne i paintComponent
-metoden til et JPanel
. Som
siste parameter ved kallet bruker vi da kort og godt this
.
Merknad De tekniske detaljene vedrørende uttegning av grafikk på skjermen er
plattformavhengige. På grunn av dette er Graphics
-klassen en abstrakt
klasse som bare spesifiserer hvilke tegnemetoder vi skal ha tilgang til. Det
Graphics
-objektet som er aktuell parameter i et kall på paint
eller paintComponent
vil være av en eller annen subklassetype som
er spesialtilpasset for det operativsystemet som programmet blir kjørt på.
Det er da også et slikt objekt som blir brukt for å kalle opp de tegnemetodene
som Graphics
-klassen spesifiserer. Hvilken konkret subklassetype
det er, trenger vi ikke å bry oss om. Det eneste vi trenger å vite er at det
er en subtype til Graphics
, slik at vi kan bruke det til å gjøre
kall på de tegnemetodene som der er spesifisert.
I vindusklassen
Bildegalleri
som er gjengitt nedenfor blir det opprettet 7 bilder i form av
ImageIcon
-objekter. De plasseres i hvert sitt panel. I panelet
blir det også lagret data for bredde og høyde på tilgjengelig tegneflate på
skjermen. Når bildene skal tegnes ut, blir det sjekket om bildehøyde er større
enn høyden på tilgjengelig tegneflate. I så fall blir en skalert versjon av
bildet tegnet ut. Skaleringen gjøres slik at forholdet mellom bredde og høyde
i den skalerte versjonen blir som i originalen.
Bildepanelene blir plassert som fanekort, der fanetittel er lik bildets tittel,
mens kunstnerens navn vises som tooltiptekst. Driverklasse for programmet finnes
i fila Bildevisning.java
.
Dersom innstillingene på din nettleser passer, kan
du få kjørt en appletversjon av programmet i din nettleser ved å klikke på følgende link:
Bildegalleri
.
1 import javax.swing.*; 2 import java.awt.*; 3 import java.net.*; 4 5 public class Bildegalleri extends JFrame 6 { 7 private int bredde, høyde; 8 private int antPaneler = 8; 9 private String[] bildefil = 10 { 11 "leonardo.jpg", "durer.jpg", "holbein.jpg", 12 "david.jpg", "rafael.jpg", 13 "rembrandt2461lr.jpg", "JulieManet.jpeg", 14 "Eugène_Delacroix_-_La_liberté_guidant_le_peuple.jpg" 15 }; 16 private String[] kunstner = 17 { 18 "Leonardo da Vinci", "Albrecht Dürer", 19 "Hans Holbein", "Louis David", "Raphael", 20 "Rembrandt", "Pierre Auguste Renoir", 21 "Eugène Delacroix" 22 }; 23 private String[] tittel = 24 { 25 "Mona Lisa", "Selvportrett", "Nikolas Kratzer", 26 "L'enlèvement des Sabines", "Den vakre gartnerinne", 27 "Selvportrett", "Julie Manet", 28 "La liberté guidant le peuple" 29 }; 30 31 public Bildegalleri() 32 { 33 super("Bildegalleri"); 34 JTabbedPane flikmappe = new JTabbedPane(); 35 Bilde[] panel = new Bilde[antPaneler]; 36 Dimension skjermstørrelse = 37 Toolkit.getDefaultToolkit().getScreenSize(); 38 bredde = skjermstørrelse.width; 39 høyde = skjermstørrelse.height - 30; //trekker fra for oppgavelinje 40 41 for (int i = 0; i < panel.length; i++) 42 { 43 URL bildeURL = null; 44 bildeURL = Bildegalleri.class.getResource( 45 "bildefiler/" + bildefil[i]); 46 if (bildeURL != null) 47 { 48 panel[i] = new Bilde(new ImageIcon(bildeURL), 49 bredde, høyde - 40); //trekker fra for flikhøyde 50 flikmappe.addTab(tittel[i], null, panel[i], kunstner[i]); 51 } 52 else 53 { 54 flikmappe.addTab("Tomt panel", new JPanel()); 55 } 56 } 57 58 flikmappe.setSelectedIndex(0); 59 Container c = getContentPane(); 60 c.add(flikmappe, BorderLayout.CENTER); 61 setSize(bredde, høyde); 62 setVisible(true); 63 } 64 } 65 66 class Bilde extends JPanel 67 { 68 private ImageIcon ikon; 69 private int bredde, høyde; 70 71 public Bilde(ImageIcon bilde, int b, int h) 72 { 73 bredde = b; 74 høyde = h; 75 ikon = bilde; 76 } 77 78 public void paintComponent(Graphics g) 79 { 80 super.paintComponent(g); 81 int bildebredde = ikon.getIconWidth(); 82 int bildehøyde = ikon.getIconHeight(); 83 if (bildehøyde > høyde) 84 { //skalerer om nødvendig: 85 bildebredde = bildebredde * høyde / bildehøyde; 86 bildehøyde = høyde; 87 } 88 if (bildebredde > bredde) 89 { 90 bildehøyde = bildehøyde * bredde / bildebredde; 91 bildebredde = bredde; 92 } 93 g.drawImage(ikon.getImage(), 0, 0, bildebredde, bildehøyde, this); 94 } 95 }
En applet kan bare laste inn bildedata fra serveren som appleten ligger på.
Dette skyldes både sikkerhetshensyn og at det er mest logisk at appletens
klassefiler og datafiler ligger på samme sted. For å laste inn bildedata fra
en server, bruker en applet et URL
-objekt på denne måte:
import java.net.*; . . . URL kodekilde = getCodeBase(); // plassering av class-filene URL bildeURL = null; ImageIcon bilde = null; try { bildeURL = new URL( kodekilde, bildefilnavn ); bilde = new ImageIcon( bildeURL ); } catch ( MalformedURLException e ) { ... } . . .
Obs! Dersom vi bruker Eclipse, vil metoden getCodeBase
returnere filstien
for rotkatalogen til Eclipse-prosjektets class-filer. Når vi angir bildefilnavn, må vi derfor angi
bildefilas relative plassering i forhold til denne katalogen.
Appleten Bildegalleri4
er en appletversjon av samme programmet som er beskrevet i Programeksempel 2 like foran.
Fullstendig kode for programmet (unntatt html-fil) er gjengitt nedenfor.
Ved å klikke på linken Bildegalleri4.html,
skal du kunne kjøre programmet i din nettleser.
1 import javax.swing.*; 2 import java.awt.*; 3 import java.net.*; 4 5 public class Bildegalleri4 extends JApplet 6 { 7 private int bredde, høyde; 8 private int antPaneler = 7; 9 private String[] bildefil = 10 { 11 "leonardo.jpg", "durer.jpg", "holbein.jpg", "david.jpg", 12 "rafael.jpg", "rembrandt2461lr.jpg", "JulieManet.jpeg" 13 }; 14 private String[] kunstner = 15 { 16 "Leonardo da Vinci", "Albrecht Dürer", "Hans Holbein", 17 "Louis David", "Raphael", "Rembrandt", "Pierre August Renoir" 18 }; 19 private String[] tittel = 20 { 21 "Mona Lisa", "Selvportrett", "Nikolas Kratzer", 22 "L'enlèvement des Sabines", "Den vakre gartnerinne", 23 "Selvportrett", "Julie Manet" 24 }; 25 26 public void init() 27 { 28 JTabbedPane flikmappe = new JTabbedPane(); 29 Bildepanel2[] panel = new Bildepanel2[antPaneler]; 30 Dimension skjermstørrelse = 31 Toolkit.getDefaultToolkit().getScreenSize(); 32 bredde = skjermstørrelse.width; 33 høyde = skjermstørrelse.height - 100; 34 URL kodekilde = getCodeBase(); 35 36 for (int i = 0; i < panel.length; i++) 37 { 38 URL bildeURL = null; 39 try 40 { 41 bildeURL = new URL(kodekilde, 42 "bildefiler/" + bildefil[ i]); 43 panel[ i] = new Bildepanel2(new ImageIcon(bildeURL), 44 bredde, høyde - 40); 45 flikmappe.addTab(tittel[i], null, panel[i], kunstner[i]); 46 } 47 catch (MalformedURLException e) 48 { 49 System.err.println("Fikk ikke opprettet URL for bildefil"); 50 } 51 } 52 53 flikmappe.setSelectedIndex(0); 54 Container c = getContentPane(); 55 c.add(flikmappe, BorderLayout.CENTER); 56 setSize(bredde, høyde); //setter appletstørrelse 57 } 58 } 59 60 class Bildepanel2 extends JPanel 61 { 62 private ImageIcon ikon; 63 private int bredde, høyde; 64 65 public Bildepanel2(ImageIcon bilde, int b, int h) 66 { 67 bredde = b; 68 høyde = h; 69 ikon = bilde; 70 } 71 72 public void paintComponent(Graphics g) 73 { 74 super.paintComponent(g); 75 int bildebredde = ikon.getIconWidth(); 76 int bildehøyde = ikon.getIconHeight(); 77 if (bildehøyde > høyde) 78 { //skalerer om nødvendig: 79 bildebredde = bildebredde * høyde / bildehøyde; 80 bildehøyde = høyde; 81 } 82 if (bildebredde > bredde) 83 { 84 bildehøyde = bildehøyde * bredde / bildebredde; 85 bildebredde = bredde; 86 } 87 g.drawImage(ikon.getImage(), 0, 0, bildebredde, bildehøyde, this); 88 } 89 }
I programmet
RepeterendeBilder
som er gjengitt nedenfor, blir de tre bildene
everest.gif,
geit.gif og
world.gif
tegnet ut rekursivt i mindre og
mindre format inntil en viss grense. Den opprinnelige kvadratiske tegneflata blir delt
inn i fire like deler ved en horisontal og en vertikal delestrek. Den delen som
ligger øverst til venstre holdes ledig, mens de tre andre blir brukt til å
tegne de tre bildene med passende skalering. Deretter gjentar dette seg, men
nå med den ledige delen som opprinnelig tegneflate. Rekursjonen stopper opp
når sidekanten i ledig tegneflate er kommet under en bestemt grense.
Resultatet blir et vindu lik det som er vist på bildet under.
1 import java.awt.*; 2 import javax.swing.*; 3 import java.net.*; 4 5 // Demonsterer rekursiv tegnerutine. 6 public class RepeterendeBilder extends JFrame 7 { 8 public RepeterendeBilder() 9 { 10 super("Repeterende bilder"); 11 getContentPane().add(new Bilderepetisjon(), BorderLayout.CENTER); 12 pack(); 13 setVisible(true); 14 } 15 16 public static void main(String[] args) 17 { 18 EventQueue.invokeLater(new Runnable() 19 { 20 public void run() 21 { 22 JFrame vindu = new RepeterendeBilder(); 23 vindu.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 24 } 25 }); 26 } 27 } 28 29 class Bilderepetisjon extends JPanel 30 { 31 private final int BREDDE = 500; 32 private final int HØYDE = 500; 33 private final int MIN = 20; // Minste bildestørrelse 34 private Image jord, everest, geit; 35 private ImageIcon jordikon, everestikon, geitikon; 36 37 public Bilderepetisjon() 38 { 39 URL bildeURL = null; 40 41 bildeURL = Bilderepetisjon.class.getResource( 42 "bildefiler/world.gif"); 43 if (bildeURL != null) 44 { 45 jordikon = new ImageIcon(bildeURL); 46 } 47 else 48 { 49 JOptionPane.showMessageDialog(null, 50 "Finner ikke bildefil world.gif."); 51 } 52 bildeURL = Bilderepetisjon.class.getResource( 53 "bildefiler/everest.gif"); 54 if (bildeURL != null) 55 { 56 everestikon = new ImageIcon(bildeURL); 57 } 58 else 59 { 60 JOptionPane.showMessageDialog(null, 61 "Finner ikke bildefil everest.gif."); 62 } 63 bildeURL = Bilderepetisjon.class.getResource( 64 "bildefiler/geit.gif"); 65 if (bildeURL != null) 66 { 67 geitikon = new ImageIcon(bildeURL); 68 } 69 else 70 { 71 JOptionPane.showMessageDialog(null, 72 "Finner ikke bildefil geit.gif."); 73 } 74 75 jord = jordikon.getImage(); 76 everest = everestikon.getImage(); 77 geit = geitikon.getImage(); 78 setPreferredSize(new Dimension(BREDDE, HØYDE)); 79 } 80 81 // Tegner det fullstendige skjermbildet rekursivt. 82 public void tegnBilder(int side, Graphics g) 83 { 84 // Tegner tre bilder i hver sin firedel av tegneflata. 85 g.drawImage(geit, 0, side / 2, side / 2, side / 2, this); 86 g.drawImage(everest, side / 2, 0, side / 2, side / 2, this); 87 g.drawImage(jord, side / 2, side / 2, side / 2, side / 2, this); 88 89 // Tegner de tre bildene om igjen med halvparten så lange 90 // sider i den ledige firedelen av vinduet, forutsatt at 91 // sidekanten er større enn den valgte minstestørrelsen. 92 if (side > MIN) 93 { 94 tegnBilder(side / 2, g); 95 } 96 } 97 98 // Setter i gang rekursjonen ved å foreta startkallet på 99 // tegnBilder-metoden. 100 public void paintComponent(Graphics g) 101 { 102 super.paintComponent(g); 103 tegnBilder(BREDDE, g); 104 } 105 }
Applikasjoner kan hente inn bilder fra en hvilken som helst adresse på
internett. Det skjer ved at det først opprettes et URL
-objekt på
grunnlag av adressen. Dette brukes som konstruktørparameter for
ImageIcon
-objektet.
I programmet
URLtest3.java
som er gjengitt nedenfor blir det hentet inn et bilde fra Musée Marmottan
i Paris (som blant annet har en omfattende samling bilder av Claude Monet),
samt et bilde fra Wikipedia. Forutsetningen for at programmet
skal virke er selvsagt at bildefilene befinner seg på de adressene som blir
brukt, og at serverne som inneholder filene er i drift.
1 import javax.swing.*; 2 import java.awt.*; 3 import java.net.*; 4 5 //Laster ned og viser bilder fra oppgitte nettadresser. 6 class Kanvas extends JPanel 7 { 8 private ImageIcon bilde; 9 10 public Kanvas(String bildeadresse) 11 { 12 try 13 { 14 bilde = new ImageIcon(new URL(bildeadresse)); 15 } 16 catch (MalformedURLException e) 17 { 18 System.err.println("Ukjent protokoll."); 19 } 20 } 21 22 public void paintComponent(Graphics g) 23 { 24 super.paintComponent(g); 25 int bildebredde = bilde.getIconWidth(); 26 int bildehøyde = bilde.getIconHeight(); 27 Dimension skjermstørrelse = 28 Toolkit.getDefaultToolkit().getScreenSize(); 29 int bredde = skjermstørrelse.width; 30 int høyde = skjermstørrelse.height - 100; //trekker fra for oppgavelinje 31 if (bildehøyde > høyde) 32 { //skalerer om nødvendig: 33 bildebredde = bildebredde * høyde / bildehøyde; 34 bildehøyde = høyde; 35 } 36 if (bildebredde > bredde) 37 { 38 bildehøyde = bildehøyde * bredde / bildebredde; 39 bildebredde = bredde; 40 } 41 g.drawImage(bilde.getImage(), 0, 0, bildebredde, bildehøyde, this); 42 } 43 44 public Dimension getPreferredSize() 45 { 46 return new Dimension(bilde.getIconWidth(), bilde.getIconHeight()); 47 } 48 } 49 50 public class URLtest3 extends JFrame 51 { 52 public URLtest3() 53 { 54 super("Visning av nedlastede bilder."); 55 JTabbedPane bildemappe = new JTabbedPane(); 56 Kanvas bilde1 = new Kanvas( 57 "http://www.marmottan.com/images/monet/Impress.jpg"); 58 bildemappe.addTab("Claude Monet", null, bilde1, 59 "Impression Soleil Levant"); 60 Kanvas bilde2 = new Kanvas( 61 "http://upload.wikimedia.org/wikipedia/commons/c/cb/Pierre-Auguste_Renoir_076.jpg"); 62 bildemappe.addTab("Pierre Auguste Renoir", null, 63 bilde2, "Jeune fille au chapeau de paille"); 64 getContentPane().add(bildemappe); 65 } 66 67 public static void main(String[] args) 68 { 69 EventQueue.invokeLater(new Runnable() 70 { 71 public void run() 72 { 73 URLtest3 test = new URLtest3(); 74 test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 75 test.pack(); 76 test.setVisible(true); 77 } 78 }); 79 } 80 }
Innholdsoversikt for programutvikling
Copyright © Kjetil Grønning og Eva Hadler Vihovde, revidert 2014