1   package fi.jyu.mit.graphics;
2   
3   import java.awt.Graphics;
4   import java.awt.image.BufferedImage;
5   import java.awt.image.WritableRaster;
6   import java.io.File;
7   import java.net.URL;
8   import java.util.Hashtable;
9   
10  import javax.imageio.ImageIO;
11  
12  
13  /**
14   * Yksinkertainen bitmapin piirto.
15   * Muunnosmatriisit vaikuttavat ainoastaan paikkaan (toistaiseksi).
16   * Bitmapista voidaan ottaa rakadata ja tehdä sille hienompia temppuja
17   * @see BufferedImage 
18   * @author vesal
19   * @version 4.9.2010
20   */
21  public class Bitmap extends BasicShape {
22  
23      private final RPoint upperLeft;
24      int imgWidth = 0;
25      int imgHeight = 0;
26  
27      private BufferedImage rawImg;
28  
29      
30      /**
31       * Luodaan bitmap tiedostosta tai URLista jos nimi alkaa http
32       * @param x koordinaatti johon bitmap näytetään
33       * @param y koordinaatti johon bitmap näytetään
34       * @param z syvyyskoordinaatti johon bitmap näytetään
35       * @param filename tiedoston nimi, josta bitmap luetaan 
36       */
37      public Bitmap(double x,double y, double z, String filename) {
38          super();
39          upperLeft = new RPoint(x,y,z);
40          try {  
41              if ( filename.startsWith("http") )
42                  rawImg = ImageIO.read(new URL(filename));
43              else
44                  rawImg = ImageIO.read(new File(filename));  
45          } catch (Exception e) {  
46              // e.printStackTrace();
47              throw new NullPointerException("filename " + filename + " not found");
48          }  
49          imgWidth = rawImg.getWidth(null);
50          imgHeight = rawImg.getHeight(null);
51      }
52  
53      
54      /**
55       * Luodaan bitmap tiedostosta
56       * @param x koordinaatti johon bitmap näytetään
57       * @param y koordinaatti johon bitmap näytetään
58       * @param filename tiedoston nimi, josta bitmap luetaan 
59       */
60      public Bitmap(double x,double y, String filename) {
61          this(x,y,0,filename);
62      }
63      
64  
65      /**
66       * Luodaan tyhjä valkoinen bitmap 
67       * @param x koordinaatti johon bitmap näytetään
68       * @param y koordinaatti johon bitmap näytetään
69       * @param z syvyyskoordinaatti johon bitmap näytetään
70       * @param w uuden kuvan leveys 
71       * @param h uuden kuvan korkeus
72       */
73      public Bitmap(double x,double y, double z, int w, int h) {
74          super();
75          upperLeft = new RPoint(x,y,z);
76          rawImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
77          imgWidth = rawImg.getWidth(null);
78          imgHeight = rawImg.getHeight(null);
79      }
80      
81      
82      /**
83       * Luodaan tyhjä valkoinen bitmap 
84       * @param x koordinaatti johon bitmap näytetään
85       * @param y koordinaatti johon bitmap näytetään
86       * @param w uuden kuvan leveys 
87       * @param h uuden kuvan korkeus
88       */
89      public Bitmap(double x,double y, int w, int h) {
90          this(x,y,0,w,h);
91      }
92      
93      
94      /**
95       * Apumetodi kopion tekemiseksi raakasta kuvasta.
96       * @param image kuvatieto joka kopioidaan
97       * @return kopioitu kuvatieto
98       */
99      public static BufferedImage cloneBufferedImage(BufferedImage image) {
100         String[] pnames = image.getPropertyNames();
101         Hashtable<String, Object> cproperties = new Hashtable<String, Object>();
102         if (pnames != null) {
103             for (int i = 0; i < pnames.length; i++) {
104                 cproperties.put(pnames[i], image.getProperty(pnames[i]));
105             }
106         }
107         WritableRaster wr = image.getRaster();
108         WritableRaster cwr = wr.createCompatibleWritableRaster();
109         cwr.setRect(wr);
110         BufferedImage cimage = new BufferedImage(image.getColorModel(), 
111                 cwr, image.isAlphaPremultiplied(), cproperties);
112         return cimage;
113     }
114     
115     
116     /**
117      * Luodaan uusi Bitmap vanhan aidoksi kopioiksi
118      * @param x koordinaatti johon bitmap näytetään
119      * @param y koordinaatti johon bitmap näytetään
120      * @param z syvyyskoordinaatti johon bitmap näytetään
121      * @param bm kopioitava kuva
122      */
123     public Bitmap(double x,double y, double z, Bitmap bm) {
124         super();
125         upperLeft = new RPoint(x,y,z);
126         rawImg = cloneBufferedImage(bm.getRawImage());
127         imgWidth = rawImg.getWidth(null);
128         imgHeight = rawImg.getHeight(null);
129     }
130     
131     
132     /**
133      * Luodaan uusi Bitmap vanhan aidoksi kopioiksi
134      * @param x koordinaatti johon bitmap näytetään
135      * @param y koordinaatti johon bitmap näytetään
136      * @param bm kopioitava kuva
137      */
138     public Bitmap(double x,double y, Bitmap bm) {
139         this(x,y,0,bm);
140     }
141     
142     
143     /**
144      * @param p pikseli jonka kirkkaus lasketaan
145      * @return pikselin kirkkaus arvona 0-255
146      */
147     public static int brightness(int p) {
148         int r = p & 0xff;
149         p >>= 8; r += p & 0xff;
150         p >>= 8; r += p & 0xff;
151         return r / 3;
152     }
153     
154 
155     /**
156      * @return kuvan leveys
157      */
158     public int getWidth() {
159         return imgWidth;
160     }
161 
162 
163     /**
164      * @return kuvan korkeus
165      */
166     public int getHeight() {
167         return imgHeight;
168     }
169     
170 
171     /**
172      * Palautetaan kuvan yhden pikselin väritiedot
173      * @param x pikselin x-koordinaatti
174      * @param y pikselin y-koordinaatti
175      * @return RGB ja alpha tieto pikselistä
176      */
177     public int getRGB(int x, int y) {
178         return rawImg.getRGB(x,y);
179     }
180     
181     
182     /**
183      * Asetetaan pikselin RGB ja alpha arvot
184      * @param x pikselin x-koordinaatti
185      * @param y pikselin y-koordinaatti
186      * @param rgb uusi RGB ja alpha arvo pikselille
187      */
188     public void setRGB(int x, int y, int rgb) {
189         rawImg.setRGB(x,y,rgb);
190     }
191     
192 
193     /**
194      * Muuttaa kolme väriä ja alpha-tiedon yhdeksi väritiedoksi
195      * @param r punaisen määrä (0-255)
196      * @param g vihreän määrä (0-255)
197      * @param b sinisen määrä (0-255)
198      * @param a alha-arvo
199      * @return tieto pakattuna yhteen 32-bit lukuun
200      */
201     public static int toRGB(int r,int g,int b,int a) {
202         return  ( a << 24 ) | (r << 16) | (g << 8) | b;
203     }
204     
205     
206     /**
207      * Muuttaa kolme väriä 
208      * @param r punaisen määrä (0-255)
209      * @param g vihreän määrä (0-255)
210      * @param b sinisen määrä (0-255)
211      * @return tieto pakattuna yhteen 32-bit lukuun
212      */
213     public static int packRGB(int r,int g,int b) {
214         return  ( 255 << 24 ) | (r << 16) | (g << 8) | b;
215     }
216     
217     
218     /**
219      * @param c väri jota tutkitaan
220      * @return väristä otettu punaisen määrä (0-255)
221      */
222     public static int getRed(int c) {
223         return (c >> 16) & 0xff;
224     }
225     
226     
227     /**
228      * @param c väri jota tutkitaan
229      * @return väristä otettu vihreän määrä (0-255)
230      */
231     public static int getGreen(int c) {
232         return (c >> 8) & 0xff;
233     }
234 
235     
236     /**
237      * @param c väri jota tutkitaan
238      * @return väristä otettu sinisen määrä (0-255)
239      */
240     public static int getBlue(int c) {
241         return (c >> 0) & 0xff;
242     }
243 
244     
245     /**
246      * @param c väri jota tutkitaan
247      * @return väristä otettu alpha-arvo
248      */
249     public static int getA(int c) {
250         return (c >> 24) & 0xff;
251     }
252     
253     
254     /**
255      * @return viite raakaan kuvadata monimutkaisempaa käsittelyä varten
256      * @see BufferedImage
257      */
258     public BufferedImage getRawImage() {
259         return rawImg;
260     }
261     
262     
263     @Override
264     protected void drawShape(Graphics g, Matrix a) {
265         SPoint sp = new SPoint(0,0);
266         a.transform(upperLeft,sp);
267         g.drawImage(rawImg,sp.getX(),sp.getY(),null);
268     }
269     
270 
271     /**
272      * Muuttaa kuvan harmaasävyiksi
273      */
274     public void convertGrayScale() {
275         for (int y = 0; y < rawImg.getHeight(); y++) {
276             for (int x = 0; x < rawImg.getWidth(); x++) {
277                 int c = rawImg.getRGB(x, y);
278                 int b = Bitmap.brightness(c);
279                 b = (b << 16) | (b << 8) | b;
280                 rawImg.setRGB(x, y, b);
281             }
282         }
283     }    
284 
285     
286     /**
287      * Tekee jokaiselle pikselille and operaation maskin kanssa.
288      * @param mask maski, jolla pikseliä muutetaan
289      */
290     public void andPixels(int mask) {
291         for (int y = 0; y < rawImg.getHeight(); y++) {
292             for (int x = 0; x < rawImg.getWidth(); x++) {
293                 int c = rawImg.getRGB(x, y);
294                 rawImg.setRGB(x, y, c & mask);
295             }
296         }
297     }    
298 
299     
300     /**
301      * Tekee jokaiselle pikselille OR operaation maskin kanssa.
302      * @param mask maski, jolla pikseliä muutetaan
303      */
304     public void orPixels(int mask) {
305         for (int y = 0; y < rawImg.getHeight(); y++) {
306             for (int x = 0; x < rawImg.getWidth(); x++) {
307                 int c = rawImg.getRGB(x, y);
308                 rawImg.setRGB(x, y, c | mask);
309             }
310         }
311     }    
312 
313     
314     /**
315      * Luodaan kuvasta 2-ulotteinen taulukko, johon kopioidaan kuvan pisteet 
316      * @param ox   - siirtymä x-suunnassa vasemmasta ylänurkasta
317      * @param oy   - siirtymä y-suunnassa vasemmasta ylänurkasta
318      * @param w    - alueen leveys josta kopioidaan
319      * @param h    - alueen korkeus josta kopioidaan
320      * @return kuvan bittitieto 2.ulotteisena kokonaislukutaulukkona
321      */
322     public int[][] getData(int ox,int oy, int w, int h) {
323         int maxx = rawImg.getWidth()-ox;
324         int maxy = rawImg.getHeight()-oy;
325         if ( ox+w < maxx ) maxx = w; 
326         if ( oy+h < maxy ) maxy = h; 
327         
328         int[][] data = new int[maxy][maxx];
329         for (int y = 0; y < maxy; y++) 
330             for (int x = 0; x < maxx; x++) 
331                 data[y][x] = rawImg.getRGB(x+ox, y+oy);
332         return data;
333     }
334     
335 
336     /**
337      * @return kuvan bittitieto 2.ulotteisena kokonaislukutaulukkona
338      */
339     public int[][] getData() {
340         return getData(0,0,rawImg.getWidth(),rawImg.getHeight());
341     }
342     
343 
344     /**
345      * Asettaa bittidatantaulukon haluttuun kohtaan kuvassa.
346      * Jos kuva menee ulos , ei ulos meneviä pisteitä huomioida.
347      * Taulukossa saa olla erimittaisia rivejä
348      * 
349      * @param ox   - siirtymä x-suunnassa vasemmasta ylänurkasta
350      * @param oy   - siirtymä y-suunnassa vasemmasta ylänurkasta
351      * @param w    - alueen leveys johon kopioidaan
352      * @param h    - alueen korkeus johon kopioidaan
353      * @param data - kopioitava taulukko
354      */
355     public void setData(int ox,int oy, int w, int h, int[][] data) {
356         //int[][] data = new int[rawImg.getHeight()][rawImg.getWidth()];
357         int imgw = rawImg.getWidth();
358         int imgh = rawImg.getHeight();
359         int maxy = data.length;  
360         if ( h < maxy ) maxy = h;
361         if ( imgh < maxy+oy ) maxy = imgh-oy;
362         for (int y=0; y<maxy;y++) {
363             int maxx = data[y].length;
364             if ( w < maxx ) maxx = w;
365             if ( imgw < maxx+ox ) maxx = imgw-ox;
366             for (int x=0; x<maxx;x++) 
367                 rawImg.setRGB(ox+x, oy+y, data[y][x]);
368         }    
369     }
370     
371     
372     /**
373      * Asettaa bittidatantaulukon haluttuun kohtaan kuvassa.
374      * Jos kuva menee ulos , ei ulos meneviä pisteitä huomioida.
375      * Taulukossa saa olla erimittaisia rivejä, 1. rivi määrää leveyden
376      * 
377      * @param ox   - siirtymä x-suunnassa vasemmasta ylänurkasta
378      * @param oy   - siirtymä y-suunnassa vasemmasta ylänurkasta
379      * @param data - kopioitava taulukko
380      */
381     public void setData(int ox,int oy,int[][] data) {
382         setData(ox,oy,data[0].length,data.length,data);
383     }
384     
385     
386 }
387