KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > ext > awt > image > GraphicsUtil


1 /*
2
3    Copyright 2001-2004 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.ext.awt.image;
19
20 import java.awt.Composite JavaDoc;
21 import java.awt.Graphics2D JavaDoc;
22 import java.awt.GraphicsConfiguration JavaDoc;
23 import java.awt.GraphicsDevice JavaDoc;
24 import java.awt.Point JavaDoc;
25 import java.awt.Rectangle JavaDoc;
26 import java.awt.RenderingHints JavaDoc;
27 import java.awt.Shape JavaDoc;
28 import java.awt.color.ColorSpace JavaDoc;
29 import java.awt.geom.AffineTransform JavaDoc;
30 import java.awt.geom.Rectangle2D JavaDoc;
31 import java.awt.image.BufferedImage JavaDoc;
32 import java.awt.image.ColorModel JavaDoc;
33 import java.awt.image.ComponentSampleModel JavaDoc;
34 import java.awt.image.DataBuffer JavaDoc;
35 import java.awt.image.DataBufferByte JavaDoc;
36 import java.awt.image.DataBufferInt JavaDoc;
37 import java.awt.image.DataBufferShort JavaDoc;
38 import java.awt.image.DataBufferUShort JavaDoc;
39 import java.awt.image.DirectColorModel JavaDoc;
40 import java.awt.image.Raster JavaDoc;
41 import java.awt.image.RenderedImage JavaDoc;
42 import java.awt.image.SampleModel JavaDoc;
43 import java.awt.image.SinglePixelPackedSampleModel JavaDoc;
44 import java.awt.image.WritableRaster JavaDoc;
45 import java.awt.image.renderable.RenderContext JavaDoc;
46 import java.awt.image.renderable.RenderableImage JavaDoc;
47 import java.lang.ref.Reference JavaDoc;
48 import java.lang.ref.WeakReference JavaDoc;
49
50 import org.apache.batik.ext.awt.RenderingHintsKeyExt;
51 import org.apache.batik.ext.awt.image.renderable.PaintRable;
52 import org.apache.batik.ext.awt.image.rendered.AffineRed;
53 import org.apache.batik.ext.awt.image.rendered.Any2LsRGBRed;
54 import org.apache.batik.ext.awt.image.rendered.Any2sRGBRed;
55 import org.apache.batik.ext.awt.image.rendered.BufferedImageCachableRed;
56 import org.apache.batik.ext.awt.image.rendered.CachableRed;
57 import org.apache.batik.ext.awt.image.rendered.FormatRed;
58 import org.apache.batik.ext.awt.image.rendered.RenderedImageCachableRed;
59 import org.apache.batik.ext.awt.image.rendered.TranslateRed;
60
61
62 /**
63  * Set of utility methods for Graphics.
64  * These generally bypass broken methods in Java2D or provide tweaked
65  * implementations.
66  *
67  * @author <a HREF="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
68  * @version $Id: GraphicsUtil.java,v 1.36 2005/03/27 08:58:32 cam Exp $
69  */

70 public class GraphicsUtil {
71
72     public static AffineTransform JavaDoc IDENTITY = new AffineTransform JavaDoc();
73
74     /**
75      * Draws <tt>ri</tt> into <tt>g2d</tt>. It does this be
76      * requesting tiles from <tt>ri</tt> and drawing them individually
77      * in <tt>g2d</tt> it also takes care of some colorspace and alpha
78      * issues.
79      * @param g2d The Graphics2D to draw into.
80      * @param ri The image to be drawn.
81      */

82     public static void drawImage(Graphics2D JavaDoc g2d,
83                                  RenderedImage JavaDoc ri) {
84         drawImage(g2d, wrap(ri));
85     }
86
87     /**
88      * Draws <tt>cr</tt> into <tt>g2d</tt>. It does this be
89      * requesting tiles from <tt>ri</tt> and drawing them individually
90      * in <tt>g2d</tt> it also takes care of some colorspace and alpha
91      * issues.
92      * @param g2d The Graphics2D to draw into.
93      * @param cr The image to be drawn.
94      */

95     public static void drawImage(Graphics2D JavaDoc g2d,
96                                  CachableRed cr) {
97
98         // System.out.println("DrawImage G: " + g2d);
99

100         AffineTransform JavaDoc at = null;
101         while (true) {
102             if (cr instanceof AffineRed) {
103                 AffineRed ar = (AffineRed)cr;
104                 if (at == null)
105                     at = ar.getTransform();
106                 else
107                     at.concatenate(ar.getTransform());
108                 cr = ar.getSource();
109                 continue;
110             } else if (cr instanceof TranslateRed) {
111                 TranslateRed tr = (TranslateRed)cr;
112                 // System.out.println("testing Translate");
113
int dx = tr.getDeltaX();
114                 int dy = tr.getDeltaY();
115                 if (at == null)
116                     at = AffineTransform.getTranslateInstance(dx, dy);
117                 else
118                     at.translate(dx, dy);
119                 cr = tr.getSource();
120                 continue;
121             }
122             break;
123         }
124         AffineTransform JavaDoc g2dAt = g2d.getTransform();
125         if ((at == null) || (at.isIdentity()))
126             at = g2dAt;
127         else
128             at.preConcatenate(g2dAt);
129
130         ColorModel JavaDoc srcCM = cr.getColorModel();
131         ColorSpace JavaDoc g2dCS = getDestinationColorSpace(g2d);
132         ColorModel JavaDoc g2dCM = getDestinationColorModel(g2d);
133         if (g2dCS == null)
134             // Assume device is sRGB
135
g2dCS = ColorSpace.getInstance(ColorSpace.CS_sRGB);
136         ColorModel JavaDoc drawCM = g2dCM;
137         if ((g2dCM == null) || !g2dCM.hasAlpha()) {
138             // If we can't find out about our device or the device
139
// does not support alpha just use SRGB unpremultiplied
140
// (Just because this seems to work for us).
141
drawCM = sRGB_Unpre;
142         }
143
144         if (cr instanceof BufferedImageCachableRed) {
145             // There is a huge win if we can use the BI directly here.
146
// This results in something like a 10x performance gain
147
// for images, the best thing is this is the common case.
148
if (g2dCS.equals(srcCM.getColorSpace()) &&
149                 drawCM.equals(srcCM)) {
150                 // System.err.println("Fast Case");
151
g2d.setTransform(at);
152                 BufferedImageCachableRed bicr;
153                 bicr = (BufferedImageCachableRed)cr;
154                 g2d.drawImage(bicr.getBufferedImage(),
155                               bicr.getMinX(), bicr.getMinY(), null);
156                 g2d.setTransform(g2dAt);
157                 return;
158             }
159         }
160
161         // Scaling down so do it before color conversion.
162
double determinant = at.getDeterminant();
163         if (!at.isIdentity() && (determinant <= 1.0)) {
164             if (at.getType() != AffineTransform.TYPE_TRANSLATION)
165                 cr = new AffineRed(cr, at, g2d.getRenderingHints());
166             else {
167                 int xloc = cr.getMinX() + (int)at.getTranslateX();
168                 int yloc = cr.getMinY() + (int)at.getTranslateY();
169                 cr = new TranslateRed(cr, xloc, yloc);
170             }
171         }
172
173         if (g2dCS != srcCM.getColorSpace()) {
174             // System.out.println("srcCS: " + srcCM.getColorSpace());
175
// System.out.println("g2dCS: " + g2dCS);
176
// System.out.println("sRGB: " +
177
// ColorSpace.getInstance(ColorSpace.CS_sRGB));
178
// System.out.println("LsRGB: " +
179
// ColorSpace.getInstance
180
// (ColorSpace.CS_LINEAR_RGB));
181
if (g2dCS == ColorSpace.getInstance(ColorSpace.CS_sRGB))
182                 cr = convertTosRGB(cr);
183             else if (g2dCS == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))
184                 cr = convertToLsRGB(cr);
185         }
186         srcCM = cr.getColorModel();
187         if (!drawCM.equals(srcCM))
188             cr = FormatRed.construct(cr, drawCM);
189
190         // Scaling up so do it after color conversion.
191
if (!at.isIdentity() && (determinant > 1.0))
192             cr = new AffineRed(cr, at, g2d.getRenderingHints());
193
194         // Now CR is in device space, so clear the g2d transform.
195
g2d.setTransform(IDENTITY);
196
197         // Ugly Hack alert. This Makes it use our SrcOver implementation
198
// Which doesn't seem to have as many bugs as the JDK one when
199
// going between different src's and destinations (of course it's
200
// also a lot slower).
201
Composite JavaDoc g2dComposite = g2d.getComposite();
202         if (g2d.getRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING) ==
203             RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING) {
204             if (SVGComposite.OVER.equals(g2dComposite)) {
205                 g2d.setComposite(SVGComposite.OVER);
206             }
207         }
208         Rectangle JavaDoc crR = cr.getBounds();
209         Shape JavaDoc clip = g2d.getClip();
210
211         try {
212             Rectangle JavaDoc clipR;
213             if (clip == null) {
214                 clip = crR;
215                 clipR = crR;
216             } else {
217                 clipR = clip.getBounds();
218
219                 if (clipR.intersects(crR) == false)
220                     return; // Nothing to draw...
221
clipR = clipR.intersection(crR);
222             }
223
224             Rectangle JavaDoc gcR = getDestinationBounds(g2d);
225             // System.out.println("ClipRects: " + clipR + " -> " + gcR);
226
if (gcR != null) {
227                 if (clipR.intersects(gcR) == false)
228                     return; // Nothing to draw...
229
clipR = clipR.intersection(gcR);
230             }
231
232             // System.out.println("Starting Draw: " + cr);
233
// long startTime = System.currentTimeMillis();
234

235             boolean useDrawRenderedImage = false;
236
237             srcCM = cr.getColorModel();
238             SampleModel JavaDoc srcSM = cr.getSampleModel();
239             if ((srcSM.getWidth()*srcSM.getHeight()) >=
240                 (clipR.width*clipR.height))
241                 // if srcSM tiles are around the clip size
242
// then just draw the renderedImage
243
useDrawRenderedImage = true;
244
245             Object JavaDoc atpHint = g2d.getRenderingHint
246                 (RenderingHintsKeyExt.KEY_AVOID_TILE_PAINTING);
247
248             if (atpHint == RenderingHintsKeyExt.VALUE_AVOID_TILE_PAINTING_ON)
249                 useDrawRenderedImage = true; //for PDF and PS transcoders
250

251             if (atpHint == RenderingHintsKeyExt.VALUE_AVOID_TILE_PAINTING_OFF)
252                 useDrawRenderedImage = false;
253
254
255             WritableRaster JavaDoc wr;
256             if (useDrawRenderedImage) {
257                 // This can be significantly faster but can also
258
// require much more memory, so we only use it when
259
// the clip size is smaller than the tile size.
260
Raster JavaDoc r = cr.getData(clipR);
261                 wr = ((WritableRaster JavaDoc)r).createWritableChild
262                     (clipR.x, clipR.y, clipR.width, clipR.height,
263                      0, 0, null);
264                 
265                 BufferedImage JavaDoc bi = new BufferedImage JavaDoc
266                     (srcCM, wr, srcCM.isAlphaPremultiplied(), null);
267                 
268                 // Any of the drawImage calls that take an
269
// Affine are prone to the 'CGGStackRestore: gstack
270
// underflow' bug on Mac OS X. This should work
271
// around that problem.
272
g2d.drawImage(bi, clipR.x, clipR.y, null);
273             } else {
274                 // Use tiles to draw image...
275
wr = Raster.createWritableRaster(srcSM, new Point JavaDoc(0,0));
276                 BufferedImage JavaDoc bi = new BufferedImage JavaDoc
277                     (srcCM, wr, srcCM.isAlphaPremultiplied(), null);
278
279                 int xt0 = cr.getMinTileX();
280                 int xt1 = xt0+cr.getNumXTiles();
281                 int yt0 = cr.getMinTileY();
282                 int yt1 = yt0+cr.getNumYTiles();
283                 int tw = srcSM.getWidth();
284                 int th = srcSM.getHeight();
285
286                 Rectangle JavaDoc tR = new Rectangle JavaDoc(0,0,tw,th);
287                 Rectangle JavaDoc iR = new Rectangle JavaDoc(0,0,0,0);
288
289                 if (false) {
290                     System.err.println("SrcCM: " + srcCM);
291                     System.err.println("CR: " + cr);
292                     System.err.println("CRR: " + crR + " TG: [" +
293                                        xt0 +"," +
294                                        yt0 +"," +
295                                        xt1 +"," +
296                                        yt1 +"] Off: " +
297                                        cr.getTileGridXOffset() +"," +
298                                        cr.getTileGridYOffset());
299                 }
300
301                 int yloc = yt0*th+cr.getTileGridYOffset();
302                 int skip = (clipR.y-yloc)/th;
303                 if (skip <0) skip = 0;
304                 yt0+=skip;
305
306                 int xloc = xt0*tw+cr.getTileGridXOffset();
307                 skip = (clipR.x-xloc)/tw;
308                 if (skip <0) skip = 0;
309                 xt0+=skip;
310
311                 int endX = clipR.x+clipR.width-1;
312                 int endY = clipR.y+clipR.height-1;
313
314                 if (false) {
315                     System.out.println("clipR: " + clipR + " TG: [" +
316                                        xt0 +"," +
317                                        yt0 +"," +
318                                        xt1 +"," +
319                                        yt1 +"] Off: " +
320                                        cr.getTileGridXOffset() +"," +
321                                        cr.getTileGridYOffset());
322                 }
323
324
325                 yloc = yt0*th+cr.getTileGridYOffset();
326                 int minX = xt0*tw+cr.getTileGridXOffset();
327                 int xStep = tw;
328                 xloc = minX;
329                 for (int y=yt0; y<yt1; y++, yloc += th) {
330                     if (yloc > endY) break;
331                     for (int x=xt0; x<xt1; x++, xloc+=xStep) {
332                         if ((xloc<minX) || (xloc > endX)) break;
333                         tR.x = xloc;
334                         tR.y = yloc;
335                         Rectangle2D.intersect(crR, tR, iR);
336
337                         WritableRaster JavaDoc twr;
338                         twr = wr.createWritableChild(0, 0,
339                                                      iR.width, iR.height,
340                                                      iR.x, iR.y, null);
341
342                         // System.out.println("Generating tile: " + twr);
343
cr.copyData(twr);
344
345                         // Make sure we only draw the region that was written.
346
BufferedImage JavaDoc subBI;
347                         subBI = bi.getSubimage(0, 0, iR.width, iR.height);
348
349                         if (false) {
350                             System.out.println("Drawing: " + tR);
351                             System.out.println("IR: " + iR);
352                         }
353
354                         // For some reason using the transform version
355
// causes a gStackUnderflow error but if I just
356
// use the drawImage with an x & y it works.
357
g2d.drawImage(subBI, iR.x, iR.y, null);
358                         // AffineTransform trans
359
// = AffineTransform.getTranslateInstance(iR.x, iR.y);
360
// g2d.drawImage(subBI, trans, null);
361

362                         // String label = "sub [" + x + ", " + y + "]: ";
363
// org.ImageDisplay.showImage
364
// (label, subBI);
365
}
366                     xStep = -xStep; // Reverse directions.
367
xloc += xStep; // Get back in bounds.
368
}
369             }
370             // long endTime = System.currentTimeMillis();
371
// System.out.println("Time: " + (endTime-startTime));
372

373
374         } finally {
375             g2d.setTransform(g2dAt);
376             g2d.setComposite(g2dComposite);
377         }
378
379         // System.out.println("Finished Draw");
380
}
381
382
383     /**
384      * Draws a <tt>Filter</tt> (<tt>RenderableImage</tt>) into a
385      * Graphics 2D after taking into account a particular
386      * <tt>RenderContext</tt>.<p>
387      *
388      * This method also attempts to unwind the rendering chain a bit.
389      * So it knows about certain operations (like affine, pad,
390      * composite), rather than applying each of these operations in
391      * turn it accounts for there affects through modifications to the
392      * Graphics2D. This avoids generating lots of intermediate images.
393      *
394      * @param g2d The Graphics to draw into.
395      * @param filter The filter to draw
396      * @param rc The render context that controls the drawing operation.
397      */

398     public static void drawImage(Graphics2D JavaDoc g2d,
399                                  RenderableImage JavaDoc filter,
400                                  RenderContext JavaDoc rc) {
401
402         AffineTransform JavaDoc origDev = g2d.getTransform();
403         Shape JavaDoc origClip = g2d.getClip();
404         RenderingHints JavaDoc origRH = g2d.getRenderingHints();
405
406         Shape JavaDoc clip = rc.getAreaOfInterest();
407         if (clip != null)
408             g2d.clip(clip);
409         g2d.transform(rc.getTransform());
410         g2d.setRenderingHints(rc.getRenderingHints());
411
412         drawImage(g2d, filter);
413
414         g2d.setTransform(origDev);
415         g2d.setClip(origClip);
416         g2d.setRenderingHints(origRH);
417     }
418
419     /**
420      * Draws a <tt>Filter</tt> (<tt>RenderableImage</tt>) into a
421      * Graphics 2D.<p>
422      *
423      * This method also attempts to unwind the rendering chain a bit.
424      * So it knows about certain operations (like affine, pad,
425      * composite), rather than applying each of these operations in
426      * turn it accounts for there affects through modifications to the
427      * Graphics2D. This avoids generating lots of intermediate images.
428      *
429      * @param g2d The Graphics to draw into.
430      * @param filter The filter to draw
431      */

432     public static void drawImage(Graphics2D JavaDoc g2d,
433                                  RenderableImage JavaDoc filter) {
434         if (filter instanceof PaintRable) {
435             PaintRable pr = (PaintRable)filter;
436             if (pr.paintRable(g2d))
437                 // paintRable succeeded so we are done...
438
return;
439         }
440
441         // Get our sources image...
442
// System.out.println("UnOpt: " + filter);
443
AffineTransform JavaDoc at = g2d.getTransform();
444         RenderedImage JavaDoc ri = filter.createRendering
445             (new RenderContext JavaDoc(at, g2d.getClip(), g2d.getRenderingHints()));
446
447         if (ri == null)
448             return;
449
450         g2d.setTransform(IDENTITY);
451         drawImage(g2d, GraphicsUtil.wrap(ri));
452         g2d.setTransform(at);
453     }
454
455     /**
456      * This is a wrapper around the system's
457      * BufferedImage.createGraphics that arranges for bi to be stored
458      * in a Rendering hint in the returned Graphics2D.
459      * This allows for accurate determination of the 'devices' size,
460      * and colorspace.
461
462      * @param bi The BufferedImage that the returned Graphics should
463      * draw into.
464      * @return A Graphics2D that draws into BufferedImage with <tt>bi</tt>
465      * stored in a rendering hint.
466      */

467     public static Graphics2D JavaDoc createGraphics(BufferedImage JavaDoc bi,
468                                             RenderingHints JavaDoc hints) {
469         Graphics2D JavaDoc g2d = bi.createGraphics();
470         if (hints != null)
471             g2d.addRenderingHints(hints);
472         g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE,
473                              new WeakReference JavaDoc(bi));
474         g2d.clip(new Rectangle JavaDoc(0, 0, bi.getWidth(), bi.getHeight()));
475         return g2d;
476     }
477
478
479     public static Graphics2D JavaDoc createGraphics(BufferedImage JavaDoc bi) {
480         Graphics2D JavaDoc g2d = bi.createGraphics();
481         g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE,
482                              new WeakReference JavaDoc(bi));
483         g2d.clip(new Rectangle JavaDoc(0, 0, bi.getWidth(), bi.getHeight()));
484         return g2d;
485     }
486
487
488     public final static boolean WARN_DESTINATION = true;
489
490     public static BufferedImage JavaDoc getDestination(Graphics2D JavaDoc g2d) {
491         Object JavaDoc o = g2d.getRenderingHint
492             (RenderingHintsKeyExt.KEY_BUFFERED_IMAGE);
493         if (o != null)
494             return (BufferedImage JavaDoc)(((Reference JavaDoc)o).get());
495
496         // Check if this is a BufferedImage G2d if so throw an error...
497
GraphicsConfiguration JavaDoc gc = g2d.getDeviceConfiguration();
498         GraphicsDevice JavaDoc gd = gc.getDevice();
499         if (WARN_DESTINATION &&
500             (gd.getType() == GraphicsDevice.TYPE_IMAGE_BUFFER) &&
501             (g2d.getRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING) !=
502                 RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING))
503             // throw new IllegalArgumentException
504
System.out.println
505                 ("Graphics2D from BufferedImage lacks BUFFERED_IMAGE hint");
506
507         return null;
508     }
509
510     public static ColorModel JavaDoc getDestinationColorModel(Graphics2D JavaDoc g2d) {
511         BufferedImage JavaDoc bi = getDestination(g2d);
512         if (bi != null)
513             return bi.getColorModel();
514
515         GraphicsConfiguration JavaDoc gc = g2d.getDeviceConfiguration();
516
517         // We are going to a BufferedImage but no hint was provided
518
// so we can't determine the destination Color Model.
519
if (gc.getDevice().getType() == GraphicsDevice.TYPE_IMAGE_BUFFER) {
520             if (g2d.getRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING) ==
521                 RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING)
522                 return sRGB_Unpre;
523
524             // System.out.println("CM: " + gc.getColorModel());
525
// System.out.println("CS: " + gc.getColorModel().getColorSpace());
526
return null;
527         }
528
529         return gc.getColorModel();
530     }
531
532     public static ColorSpace JavaDoc getDestinationColorSpace(Graphics2D JavaDoc g2d) {
533         ColorModel JavaDoc cm = getDestinationColorModel(g2d);
534         if (cm != null) return cm.getColorSpace();
535
536         return null;
537     }
538
539     public static Rectangle JavaDoc getDestinationBounds(Graphics2D JavaDoc g2d) {
540         BufferedImage JavaDoc bi = getDestination(g2d);
541         if (bi != null)
542             return new Rectangle JavaDoc(0, 0, bi.getWidth(), bi.getHeight());
543
544         GraphicsConfiguration JavaDoc gc = g2d.getDeviceConfiguration();
545
546         // We are going to a BufferedImage but no hint was provided
547
// so we can't determine the destination bounds.
548
if (gc.getDevice().getType() == GraphicsDevice.TYPE_IMAGE_BUFFER)
549             return null;
550
551         // This is a JDK 1.3ism, so we will just return null...
552
// return gc.getBounds();
553
return null;
554     }
555
556
557     /**
558      * Standard prebuilt Linear_sRGB color model with no alpha */

559     public final static ColorModel JavaDoc Linear_sRGB =
560         new DirectColorModel JavaDoc(ColorSpace.getInstance
561                              (ColorSpace.CS_LINEAR_RGB), 24,
562                              0x00FF0000, 0x0000FF00,
563                              0x000000FF, 0x0, false,
564                              DataBuffer.TYPE_INT);
565     /**
566      * Standard prebuilt Linear_sRGB color model with premultiplied alpha.
567      */

568     public final static ColorModel JavaDoc Linear_sRGB_Pre =
569         new DirectColorModel JavaDoc(ColorSpace.getInstance
570                              (ColorSpace.CS_LINEAR_RGB), 32,
571                              0x00FF0000, 0x0000FF00,
572                              0x000000FF, 0xFF000000, true,
573                              DataBuffer.TYPE_INT);
574     /**
575      * Standard prebuilt Linear_sRGB color model with unpremultiplied alpha.
576      */

577     public final static ColorModel JavaDoc Linear_sRGB_Unpre =
578         new DirectColorModel JavaDoc(ColorSpace.getInstance
579                              (ColorSpace.CS_LINEAR_RGB), 32,
580                              0x00FF0000, 0x0000FF00,
581                              0x000000FF, 0xFF000000, false,
582                              DataBuffer.TYPE_INT);
583
584     /**
585      * Standard prebuilt sRGB color model with no alpha.
586      */

587     public final static ColorModel JavaDoc sRGB =
588         new DirectColorModel JavaDoc(ColorSpace.getInstance
589                              (ColorSpace.CS_sRGB), 24,
590                              0x00FF0000, 0x0000FF00,
591                              0x000000FF, 0x0, false,
592                              DataBuffer.TYPE_INT);
593     /**
594      * Standard prebuilt sRGB color model with premultiplied alpha.
595      */

596     public final static ColorModel JavaDoc sRGB_Pre =
597         new DirectColorModel JavaDoc(ColorSpace.getInstance
598                              (ColorSpace.CS_sRGB), 32,
599                              0x00FF0000, 0x0000FF00,
600                              0x000000FF, 0xFF000000, true,
601                              DataBuffer.TYPE_INT);
602     /**
603      * Standard prebuilt sRGB color model with unpremultiplied alpha.
604      */

605     public final static ColorModel JavaDoc sRGB_Unpre =
606         new DirectColorModel JavaDoc(ColorSpace.getInstance
607                              (ColorSpace.CS_sRGB), 32,
608                              0x00FF0000, 0x0000FF00,
609                              0x000000FF, 0xFF000000, false,
610                              DataBuffer.TYPE_INT);
611
612     /**
613      * Method that returns either Linear_sRGB_Pre or Linear_sRGB_UnPre
614      * based on premult flag.
615      * @param premult True if the ColorModel should have premultiplied alpha.
616      * @return a ColorMdoel with Linear sRGB colorSpace and
617      * the alpha channel set in accordance with
618      * <tt>premult</tt>
619      */

620     public static ColorModel JavaDoc makeLinear_sRGBCM(boolean premult) {
621         if (premult)
622             return Linear_sRGB_Pre;
623         return Linear_sRGB_Unpre;
624     }
625
626     /**
627      * Constructs a BufferedImage with a linear sRGB colorModel, and alpha.
628      * @param width The desired width of the BufferedImage
629      * @param height The desired height of the BufferedImage
630      * @param premult The desired state of alpha premultiplied
631      * @return The requested BufferedImage.
632      */

633     public static BufferedImage JavaDoc makeLinearBufferedImage(int width,
634                                                         int height,
635                                                         boolean premult) {
636         ColorModel JavaDoc cm = makeLinear_sRGBCM(premult);
637         WritableRaster JavaDoc wr = cm.createCompatibleWritableRaster(width, height);
638         return new BufferedImage JavaDoc(cm, wr, premult, null);
639     }
640
641     /**
642      * This method will return a CacheableRed that has it's data in
643      * the linear sRGB colorspace. If <tt>src</tt> is already in
644      * linear sRGB then this method does nothing and returns <tt>src</tt>.
645      * Otherwise it creates a transform that will convert
646      * <tt>src</tt>'s output to linear sRGB and returns that CacheableRed.
647      *
648      * @param src The image to convert to linear sRGB.
649      * @return An equivilant image to <tt>src</tt> who's data is in
650      * linear sRGB.
651      */

652     public static CachableRed convertToLsRGB(CachableRed src) {
653         ColorModel JavaDoc cm = src.getColorModel();
654         ColorSpace JavaDoc cs = cm.getColorSpace();
655         if (cs == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))
656             return src;
657
658         return new Any2LsRGBRed(src);
659     }
660
661     /**
662      * This method will return a CacheableRed that has it's data in
663      * the sRGB colorspace. If <tt>src</tt> is already in
664      * sRGB then this method does nothing and returns <tt>src</tt>.
665      * Otherwise it creates a transform that will convert
666      * <tt>src</tt>'s output to sRGB and returns that CacheableRed.
667      *
668      * @param src The image to convert to sRGB.
669      * @return An equivilant image to <tt>src</tt> who's data is in sRGB.
670      */

671     public static CachableRed convertTosRGB(CachableRed src) {
672         ColorModel JavaDoc cm = src.getColorModel();
673         ColorSpace JavaDoc cs = cm.getColorSpace();
674         if (cs == ColorSpace.getInstance(ColorSpace.CS_sRGB))
675             return src;
676
677         return new Any2sRGBRed(src);
678     }
679
680     /**
681      * Convertes any RenderedImage to a CacheableRed. <p>
682      * If <tt>ri</tt> is already a CacheableRed it casts it down and
683      * returns it.<p>
684      *
685      * In cases where <tt>ri</tt> is not already a CacheableRed it
686      * wraps <tt>ri</tt> with a helper class. The wrapped
687      * CacheableRed "Pretends" that it has no sources since it has no
688      * way of inteligently handling the dependency/dirty region calls
689      * if it exposed the source.
690      * @param ri The RenderedImage to convert.
691      * @return a CacheableRed that contains the same data as ri.
692      */

693     public static CachableRed wrap(