1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63:
64:
70: public class BufferedImageGraphics extends CairoGraphics2D
71: {
72:
75: private BufferedImage image, buffer;
76:
77:
80: private int imageWidth, imageHeight;
81:
82:
85: CairoSurface surface;
86:
87:
90: static WeakHashMap<BufferedImage, CairoSurface> bufferedImages
91: = new WeakHashMap<BufferedImage, CairoSurface>();
92:
93:
96: private long cairo_t;
97:
98: private boolean hasFastCM;
99: private boolean hasAlpha;
100:
101:
102: public BufferedImageGraphics(BufferedImage bi)
103: {
104: this.image = bi;
105: imageWidth = bi.getWidth();
106: imageHeight = bi.getHeight();
107:
108: if (!(image.getSampleModel() instanceof SinglePixelPackedSampleModel))
109: hasFastCM = false;
110: else if(bi.getColorModel().equals(CairoSurface.cairoCM_opaque))
111: {
112: hasFastCM = true;
113: hasAlpha = false;
114: }
115: else if(bi.getColorModel().equals(CairoSurface.cairoColorModel)
116: || bi.getColorModel().equals(CairoSurface.cairoCM_pre))
117: {
118: hasFastCM = true;
119: hasAlpha = true;
120: }
121: else
122: hasFastCM = false;
123:
124:
125: if( bufferedImages.get( bi ) != null )
126: surface = bufferedImages.get( bi );
127: else
128: {
129: surface = new CairoSurface( imageWidth, imageHeight );
130: bufferedImages.put(bi, surface);
131: }
132:
133: cairo_t = surface.newCairoContext();
134:
135:
136: Raster raster = bi.getRaster();
137: int[] pixels;
138:
139: if (hasFastCM)
140: {
141: SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel();
142: int minX = image.getRaster().getSampleModelTranslateX();
143: int minY = image.getRaster().getSampleModelTranslateY();
144:
145:
146: pixels = ((DataBufferInt)raster.getDataBuffer()).getData();
147:
148:
149:
150: if (!(sm.getScanlineStride() == imageWidth && minX == 0 && minY == 0))
151: {
152: int[] pixels2 = new int[imageWidth * imageHeight];
153: int scanline = sm.getScanlineStride();
154:
155: for (int i = 0; i < imageHeight; i++)
156: System.arraycopy(pixels, (i - minY) * scanline - minX, pixels2,
157: i * imageWidth, imageWidth);
158:
159: pixels = pixels2;
160: }
161:
162:
163: if( !hasAlpha )
164: for(int i = 0; i < pixels.length; i++)
165: pixels[i] &= 0xFFFFFFFF;
166: }
167: else
168: {
169: pixels = CairoGraphics2D.findSimpleIntegerArray(image.getColorModel(),
170: image.getData());
171: if (pixels != null)
172: System.arraycopy(pixels, 0, surface.getData(),
173: 0, pixels.length);
174: }
175:
176: setup( cairo_t );
177: setClip(0, 0, imageWidth, imageHeight);
178: }
179:
180: BufferedImageGraphics(BufferedImageGraphics copyFrom)
181: {
182: image = copyFrom.image;
183: surface = copyFrom.surface;
184: cairo_t = surface.newCairoContext();
185: imageWidth = copyFrom.imageWidth;
186: imageHeight = copyFrom.imageHeight;
187:
188: hasFastCM = copyFrom.hasFastCM;
189: hasAlpha = copyFrom.hasAlpha;
190:
191: copy( copyFrom, cairo_t );
192: }
193:
194:
197: private void updateBufferedImage(int x, int y, int width, int height)
198: {
199: Rectangle bounds = new Rectangle(x, y, width, height);
200: bounds = getTransformedBounds(bounds, transform).getBounds();
201: x = bounds.x;
202: y = bounds.y;
203: width = bounds.width;
204: height = bounds.height;
205:
206: int[] pixels = surface.getData();
207:
208: if( x > imageWidth || y > imageHeight )
209: return;
210:
211:
212: if (height < 0)
213: {
214: y += height;
215: height = -height;
216: }
217: if (width < 0)
218: {
219: x += width;
220: width = -width;
221: }
222:
223:
224: if( x < 0 )
225: x = 0;
226: if( y < 0 )
227: y = 0;
228:
229: if( x + width > imageWidth )
230: width = imageWidth - x;
231: if( y + height > imageHeight )
232: height = imageHeight - y;
233:
234: if(!hasFastCM)
235: {
236: image.setRGB(x, y, width, height, pixels,
237: x + y * imageWidth, imageWidth);
238:
239:
240:
241:
242:
243:
244: }
245: else
246: {
247: int[] db = ((DataBufferInt)image.getRaster().getDataBuffer()).
248: getData();
249:
250:
251:
252: SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel() ;
253:
254: int minX = image.getRaster().getSampleModelTranslateX();
255: int minY = image.getRaster().getSampleModelTranslateY();
256:
257: if (sm.getScanlineStride() == imageWidth && minX == 0)
258: {
259: System.arraycopy(pixels, y * imageWidth,
260: db, (y - minY) * imageWidth,
261: height * imageWidth);
262: }
263: else
264: {
265: int scanline = sm.getScanlineStride();
266: for (int i = y; i < (height + y); i++)
267: System.arraycopy(pixels, i * imageWidth + x, db,
268: (i - minY) * scanline + x - minX, width);
269:
270: }
271: }
272: }
273:
274:
277: public Graphics create()
278: {
279: return new BufferedImageGraphics(this);
280: }
281:
282: public GraphicsConfiguration getDeviceConfiguration()
283: {
284: return null;
285: }
286:
287: protected Rectangle2D getRealBounds()
288: {
289: return new Rectangle2D.Double(0.0, 0.0, imageWidth, imageHeight);
290: }
291:
292: public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy)
293: {
294: surface.copyAreaNative(x, y, width, height, dx, dy, surface.width);
295: updateBufferedImage(x + dx, y + dy, width, height);
296: }
297:
298:
302: public void draw(Shape s)
303: {
304:
305: Rectangle r = findStrokedBounds(s);
306: if (shiftDrawCalls)
307: {
308: r.width++;
309: r.height++;
310: }
311:
312:
313: if (comp == null || comp instanceof AlphaComposite)
314: {
315: super.draw(s);
316: updateBufferedImage(r.x, r.y, r.width, r.height);
317: }
318: else
319: {
320: createBuffer();
321:
322: Graphics2D g2d = (Graphics2D)buffer.getGraphics();
323: g2d.setStroke(this.getStroke());
324: g2d.setColor(this.getColor());
325: g2d.setTransform(transform);
326: g2d.draw(s);
327:
328: drawComposite(r.getBounds2D(), null);
329: }
330: }
331:
332: public void fill(Shape s)
333: {
334: if (comp == null || comp instanceof AlphaComposite)
335: {
336: super.fill(s);
337: Rectangle r = s.getBounds();
338: updateBufferedImage(r.x, r.y, r.width, r.height);
339: }
340: else
341: {
342: createBuffer();
343:
344: Graphics2D g2d = (Graphics2D)buffer.getGraphics();
345: g2d.setPaint(this.getPaint());
346: g2d.setColor(this.getColor());
347: g2d.setTransform(transform);
348: g2d.fill(s);
349:
350: drawComposite(s.getBounds2D(), null);
351: }
352: }
353:
354: public void drawRenderedImage(RenderedImage image, AffineTransform xform)
355: {
356: if (comp == null || comp instanceof AlphaComposite)
357: {
358: super.drawRenderedImage(image, xform);
359: updateBufferedImage(0, 0, imageWidth, imageHeight);
360: }
361: else
362: {
363: createBuffer();
364:
365: Graphics2D g2d = (Graphics2D)buffer.getGraphics();
366: g2d.setRenderingHints(this.getRenderingHints());
367: g2d.setTransform(transform);
368: g2d.drawRenderedImage(image, xform);
369:
370: drawComposite(buffer.getRaster().getBounds(), null);
371: }
372:
373: }
374:
375: protected boolean drawImage(Image img, AffineTransform xform,
376: Color bgcolor, ImageObserver obs)
377: {
378: if (comp == null || comp instanceof AlphaComposite)
379: {
380: boolean rv = super.drawImage(img, xform, bgcolor, obs);
381: updateBufferedImage(0, 0, imageWidth, imageHeight);
382: return rv;
383: }
384: else
385: {
386:
387: if( !(img instanceof BufferedImage) )
388: {
389: ImageProducer source = img.getSource();
390: if (source == null)
391: return false;
392: img = Toolkit.getDefaultToolkit().createImage(source);
393: }
394: BufferedImage bImg = (BufferedImage) img;
395:
396:
397: Rectangle2D bounds = new Rectangle(bImg.getMinX(), bImg.getMinY(),
398: bImg.getWidth(), bImg.getHeight());
399: if (xform != null)
400: bounds = getTransformedBounds(bounds, xform);
401:
402:
403: createBuffer();
404:
405: Graphics2D g2d = (Graphics2D)buffer.getGraphics();
406: g2d.setRenderingHints(this.getRenderingHints());
407: g2d.drawImage(img, xform, obs);
408:
409:
410: return drawComposite(bounds, obs);
411: }
412: }
413:
414: public void drawGlyphVector(GlyphVector gv, float x, float y)
415: {
416:
417: Rectangle2D bounds = gv.getLogicalBounds();
418: bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
419: bounds.getWidth(), bounds.getHeight());
420:
421:
422: if (comp == null || comp instanceof AlphaComposite)
423: {
424: super.drawGlyphVector(gv, x, y);
425:
426:
427:
428: bounds = bounds.getBounds();
429:
430: updateBufferedImage((int)bounds.getX(), (int)bounds.getY(),
431: (int)bounds.getWidth(), (int)bounds.getHeight());
432: }
433: else
434: {
435: createBuffer();
436:
437: Graphics2D g2d = (Graphics2D)buffer.getGraphics();
438: g2d.setPaint(this.getPaint());
439: g2d.setStroke(this.getStroke());
440: g2d.setTransform(transform);
441: g2d.drawGlyphVector(gv, x, y);
442:
443: drawComposite(bounds, null);
444: }
445: }
446:
447:
457: private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
458: {
459:
460: bounds = getTransformedBounds(bounds, transform);
461:
462:
463: Rectangle2D devClip = this.getClipInDevSpace();
464: Rectangle2D.intersect(bounds, devClip, bounds);
465: devClip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
466: buffer.getWidth(), buffer.getHeight());
467: Rectangle2D.intersect(bounds, devClip, bounds);
468:
469:
470:
471: double x = bounds.getX();
472: double y = bounds.getY();
473: double maxX = x + bounds.getWidth();
474: double maxY = y + bounds.getHeight();
475: x = Math.round(x);
476: y = Math.round(y);
477: bounds.setRect(x, y, Math.round(maxX - x), Math.round(maxY - y));
478:
479:
480: BufferedImage buffer2 = buffer;
481: if (!bounds.equals(buffer2.getRaster().getBounds()))
482: buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
483: (int)bounds.getWidth(),
484: (int)bounds.getHeight());
485:
486:
487: BufferedImage current = image;
488: current = current.getSubimage((int)bounds.getX(), (int)bounds.getY(),
489: (int)bounds.getWidth(),
490: (int)bounds.getHeight());
491:
492:
493: compCtx.compose(buffer2.getRaster(), current.getRaster(),
494: current.getRaster());
495:
496:
497:
498: Composite oldcomp = comp;
499: setComposite(AlphaComposite.Src);
500:
501:
502:
503:
504: boolean rv = super.drawImage(current,
505: AffineTransform.getTranslateInstance(bounds.getX(),
506: bounds.getY()),
507: null, null);
508: setComposite(oldcomp);
509: updateColor();
510: return rv;
511: }
512:
513: private void createBuffer()
514: {
515: if (buffer == null)
516: {
517: buffer = new BufferedImage(image.getWidth(), image.getHeight(),
518: BufferedImage.TYPE_INT_ARGB);
519: }
520: else
521: {
522: Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
523:
524: g2d.setBackground(new Color(0,0,0,0));
525: g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
526: }
527: }
528:
529: protected ColorModel getNativeCM()
530: {
531: return image.getColorModel();
532: }
533:
534: protected ColorModel getBufferCM()
535: {
536: return ColorModel.getRGBdefault();
537: }
538: }