Ignore:
Timestamp:
05/10/18 16:04:51 (6 years ago)
Author:
davidb
Message:

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/expeditee/items/Picture.java

    r1047 r1102  
    1919package org.expeditee.items;
    2020
    21 import java.awt.AlphaComposite;
    22 import java.awt.BasicStroke;
    23 import java.awt.Color;
    24 import java.awt.Graphics2D;
    25 import java.awt.Image;
    26 import java.awt.Point;
    27 import java.awt.Polygon;
    28 import java.awt.Rectangle;
    29 import java.awt.Shape;
    30 import java.awt.Stroke;
    31 import java.awt.Toolkit;
    32 import java.awt.geom.AffineTransform;
    33 import java.awt.geom.Point2D;
    34 import java.awt.image.BufferedImage;
    35 import java.awt.image.CropImageFilter;
    36 import java.awt.image.FilteredImageSource;
    37 import java.awt.image.ImageObserver;
    38 import java.awt.image.PixelGrabber;
    3921import java.io.File;
    4022import java.io.IOException;
    4123import java.text.DecimalFormat;
    42 
    43 import javax.imageio.ImageIO;
    44 import javax.swing.ImageIcon;
    4524
    4625import org.apache.commons.cli.CommandLine;
     
    4928import org.apache.commons.cli.Options;
    5029import org.apache.commons.cli.ParseException;
    51 import org.expeditee.gui.DisplayIO;
     30import org.expeditee.core.Clip;
     31import org.expeditee.core.Colour;
     32import org.expeditee.core.Dimension;
     33import org.expeditee.core.EnforcedClipStack.EnforcedClipKey;
     34import org.expeditee.core.Image;
     35import org.expeditee.core.Point;
     36import org.expeditee.core.Stroke;
     37import org.expeditee.core.bounds.AxisAlignedBoxBounds;
     38import org.expeditee.core.bounds.CombinationBoxBounds;
     39import org.expeditee.core.bounds.PolygonBounds;
     40import org.expeditee.gio.EcosystemManager;
     41import org.expeditee.gio.GraphicsManager;
     42import org.expeditee.gui.DisplayController;
    5243import org.expeditee.gui.FrameGraphics;
    5344import org.expeditee.gui.FrameIO;
    54 import org.expeditee.gui.FrameMouseActions;
    5545import org.expeditee.gui.FrameUtils;
    56 import org.expeditee.items.widgets.InteractiveWidget;
    57 import org.expeditee.stats.Logger;
    5846
    5947/**
     
    7563 */
    7664public class Picture extends XRayable {
     65       
     66        private static final float CROPPING_COMPOSITE_ALPHA = 0.5f;
    7767
    7868        private static final int MINIMUM_WIDTH = 10;
     
    114104        private String _fileName = null;
    115105
    116         // used to repaint animated GIF images, among other things.
    117         protected ImageObserver _imageObserver = null;
    118 
    119         protected Picture(Text source, ImageObserver observer, Image image) {
     106        protected Picture(Text source, Image image) {
    120107                super(source);
    121                 _imageObserver = observer;
    122108                _image = image;
    123109
     
    150136         *            screen.
    151137         */
    152         public Picture(Text source, String fileName, String path, String size,
    153                         ImageObserver observer) {
     138        public Picture(Text source, String fileName, String path, String size)
     139        {
    154140                super(source);
    155                 _imageObserver = observer;
    156141                _fileName = fileName;
    157142                _path = path;
     
    226211
    227212                // set the default values for start and end
    228                 _start.setLocation(0, 0);
     213                _start.set(0, 0);
    229214                if (_image == null)
    230                         _end.setLocation(0, 0);
     215                        _end.set(0, 0);
    231216                else
    232                         _end.setLocation(_image.getWidth(null), _image.getHeight(null));
     217                        _end.set(_image.getWidth(), _image.getHeight());
    233218                size = size.trim();
    234219                String sizeLower = size.toLowerCase();
     
    272257                try {
    273258                        if (size.length() == 0) {
    274                                 size = "" + _image.getWidth(null);
     259                                size = "" + _image.getWidth();
    275260                                _source.setText(getTagText() + size);
    276261                                return;
     
    293278        }
    294279
     280        public void setStartCrop(Point p)
     281        {
     282                if (p != null) setStartCrop(p.x, p.y);
     283        }
     284       
    295285        public void setStartCrop(int x, int y) {
    296286                invalidateCroppedArea();
    297287                _cropStart = new Point(x - getX(), y - getY());
    298288                invalidateCroppedArea();
     289        }
     290
     291        public void setEndCrop(Point p)
     292        {
     293                if (p != null) setEndCrop(p.x, p.y);
    299294        }
    300295
     
    312307                        int startY = getY() + topLeft.y - _highlightThickness;
    313308                        int border = 2 * _highlightThickness;
    314                         invalidate(new Rectangle(startX, startY, bottomRight.x - topLeft.x
    315                                         + 2 * border, bottomRight.y - topLeft.y + 2 * border));
     309                        // TODO: Why invalidate specific area just before invalidateAll? cts16
     310                        invalidate(new AxisAlignedBoxBounds(startX, startY,
     311                                        bottomRight.x - topLeft.x + 2 * border, bottomRight.y - topLeft.y + 2 * border));
    316312                        invalidateAll();
    317313                } else {
     
    325321        }
    326322
    327         public Point getBottomRightCrop() {
    328                 return new Point(Math.max(_cropStart.x, _cropEnd.x), Math.max(
    329                                 _cropStart.y, _cropEnd.y));
     323        public Point getBottomRightCrop()
     324        {
     325                return new Point(Math.max(_cropStart.x, _cropEnd.x), Math.max(_cropStart.y, _cropEnd.y));
    330326        }
    331327
     
    335331                invalidateCroppedArea();
    336332        }
    337 
    338         public boolean isCropTooSmall() {
    339                 if (_cropStart == null || _cropEnd == null)
    340                         return true;
     333       
     334        public boolean isBeingCropped()
     335        {
     336                return (_cropStart != null && _cropEnd != null);
     337        }
     338
     339        public boolean isCropTooSmall()
     340        {
     341                if (!isBeingCropped()) return true;
    341342
    342343                int cropWidth = Math.abs(_cropEnd.x - _cropStart.x);
     
    353354        }
    354355
    355         public void updatePolygon() {
     356        public PolygonBounds updateBounds()
     357        {
    356358                if (_image == null) {
    357359                        refresh();
     
    360362               
    361363                Point[] ori = new Point[4];
    362                 Point2D[] rot = new Point2D[4];
    363364                Point centre = new Point();
    364365
     
    393394                        centre.y = base_y + (bottomRight.y - topLeft.y) / 2;
    394395                       
    395                         Rectangle clip = new Rectangle(topLeft.x + base_x,
     396                        AxisAlignedBoxBounds clip = new AxisAlignedBoxBounds(topLeft.x + base_x,
    396397                                        topLeft.y + base_y, bottomRight.x - topLeft.x,
    397                                         bottomRight.y - topLeft.y).getBounds();
     398                                        bottomRight.y - topLeft.y);
    398399//                      _poly.addPoint((int) clip.getMinX() - 1, (int) clip.getMinY() - 1);
    399400//                      _poly.addPoint((int) clip.getMinX() - 1, (int) clip.getMaxY());
     
    408409                }
    409410               
    410                 AffineTransform.getRotateInstance(Math.PI * _rotate / 180, centre.x, centre.y).transform(ori, 0, rot, 0, 4);
    411                
    412                 _poly = new Polygon();
    413                 for(Point2D p : rot) {
    414                         _poly.addPoint((int)p.getX(), (int)p.getY());
    415                 }
     411                PolygonBounds poly = new PolygonBounds();
     412                for (Point p : ori) {
     413                        poly.addPoint(p);
     414                }
     415                poly.rotate(Math.PI * _rotate / 180, centre);
     416               
     417                return poly.close();
    416418        }
    417419
     
    454456         */
    455457        @Override
    456         protected void paintLink(Graphics2D g) {
    457                 if (FrameGraphics.isAudienceMode())
    458                         return;
    459                 super.paintLink(g);
    460         }
    461        
    462         public void paintImageTiling(Graphics2D g) {
    463                 if (_image == null) {
    464                         return;
    465                 }
    466                
    467                 int iw = _image.getWidth(null);
    468                 int ih = _image.getHeight(null);
    469                 if(iw <= 0 || ih <= 0) {
    470                         return;
    471                 }
    472                
    473                 int base_x = (_anchorLeft!=null) ? _anchorLeft : _source.getX();
    474                 int base_y = (_anchorTop!=null) ? _anchorTop : _source.getY();
     458        protected void paintLink()
     459        {
     460                if (DisplayController.isAudienceMode()) return;
     461                super.paintLink();
     462        }
     463       
     464        /**
     465         * Paint the image repeatedly tiled over the drawing area.
     466         */
     467        public void paintImageTiling()
     468        {       
     469                if (_image == null) return;
     470               
     471                int iw = _image.getWidth();
     472                int ih = _image.getHeight();
     473                if(iw <= 0 || ih <= 0) return;
     474               
     475                int base_x = (_anchorLeft != null) ? _anchorLeft : _source.getX();
     476                int base_y = (_anchorTop != null) ? _anchorTop : _source.getY();
    475477               
    476478                int dX1 = base_x;
     
    479481                int dY2 = base_y + getHeight();
    480482               
    481                 BufferedImage tmp = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
    482                 Graphics2D g2d = tmp.createGraphics();
     483                Image tmp = Image.createImage(getWidth(), getHeight());
     484                EcosystemManager.getGraphicsManager().pushDrawingSurface(tmp);
     485
    483486                int offX = (tmp.getWidth() - getWidth()) / 2;
    484487                int offY = (tmp.getHeight() - getHeight()) / 2;
    485                
    486                 // g2d.rotate(rotate, tmp.getWidth() / 2, tmp.getHeight() / 2);
    487488               
    488489                int cropStartX = _start.x;
     
    491492                cropEndX = iw;
    492493        }
     494       
    493495                for(int x = dX1; x < dX2; ) {
    494496                        // end - start = (cropEnd - cropStart) * scale
     
    506508                        cropEndY = ih;
    507509                }
     510               
    508511                        for(int y = dY1; y < dY2; ) {
    509512                                int h = (int) ((cropEndY - cropStartY) * _scale);
     
    518521                                int sy = _flipY ? cropEndY : cropStartY;
    519522                                int ey = _flipY ? cropStartY : cropEndY;
    520                                 g2d.drawImage(_image, x - dX1 + offX, y - dY1 + offY, endX - dX1 + offX, endY - dY1 + offY, sx, sy, ex, ey, null);
     523                               
     524                                Point topLeft = new Point(x - dX1 + offX, y - dY1 + offY);
     525                                Dimension size = new Dimension(endX - x, endY - y);
     526                                Point cropTopLeft = new Point(sx, sy);
     527                                Dimension cropSize = new Dimension(ex - sx, ey - sy);
     528                                if (cropSize.width > 0 && cropSize.height > 0) {
     529                                        EcosystemManager.getGraphicsManager().drawImage(_image, topLeft, size, 0.0, cropTopLeft, cropSize);
     530                                }
    521531                               
    522532                                cropStartY = 0;
     
    531541                        x = endX;
    532542                }
    533                
    534                 AffineTransform at = new AffineTransform();
    535                 at.translate(dX1, dY1);
    536                 at.rotate(Math.PI * _rotate / 180, tmp.getWidth() / 2, tmp.getHeight() / 2);
    537                 g.drawImage(tmp, at, _imageObserver);
    538                 // g.drawImage(tmp, dX1, dY1, dX2, dY2, 0, 0, tmp.getWidth(), tmp.getHeight(), _imageObserver);
    539         }
    540 
    541         @Override
    542         public void paint(Graphics2D g) {
    543                 if (_image == null)
    544                         return;
    545 
    546                 paintLink(g);
    547 
    548                 // if we are showing the cropping, then show the original as transparent
     543
     544                EcosystemManager.getGraphicsManager().popDrawingSurface();
     545                EcosystemManager.getGraphicsManager().drawImage(tmp, new Point(dX1, dY1), null, Math.PI * _rotate / 180);
     546                tmp.releaseImage();
     547        }
     548
     549        @Override
     550        public void paint()
     551        {
     552                if (_image == null) return;
     553
     554                paintLink();
     555               
     556                GraphicsManager g = EcosystemManager.getGraphicsManager();
     557
     558                // if we are showing the cropping
    549559                if (_showCropping && !isCropTooSmall()) {
    550                         // show the full image as transparent
    551                         float alpha = .5f;
    552                         g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
    553                                         alpha));
    554                        
    555                         paintImageTiling(g);
    556 
    557                         g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
    558                                         1.0f));
     560                        // show the uncropped area as transparent
     561                        g.setCompositeAlpha(CROPPING_COMPOSITE_ALPHA);
     562                        paintImageTiling();
     563                        g.setCompositeAlpha(1.0f);
     564                       
    559565                        // show the cropped area normally
    560566                        Point topLeft = getTopLeftCrop();
    561567                        Point bottomRight = getBottomRightCrop();
    562                         int base_x = (_anchorLeft!=null) ? _anchorLeft : _source.getX();
    563                         int base_y = (_anchorTop!=null) ? _anchorTop : _source.getY();
    564                        
    565                         Shape clip = new Rectangle(base_x + topLeft.x, base_y + topLeft.y,
    566                                         bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
    567                         g.setColor(getPaintHighlightColor());
    568                         g.draw(clip);
    569                         g.setClip(clip);
    570 
    571                         paintImageTiling(g);
    572                        
    573                         g.draw(clip);
    574                         // if the image is cropped, but we are not showing the cropping
    575                         // otherwise, paint normally
     568                        int base_x = (_anchorLeft != null) ? _anchorLeft : _source.getX();
     569                        int base_y = (_anchorTop != null) ? _anchorTop : _source.getY();
     570                       
     571                        Clip clip = new Clip(new AxisAlignedBoxBounds(  base_x + topLeft.x,
     572                                                                                                                                        base_y + topLeft.y,
     573                                                                                                                                        bottomRight.x - topLeft.x,
     574                                                                                                                                        bottomRight.y - topLeft.y));
     575                        EnforcedClipKey key = g.pushClip(clip);
     576                        paintImageTiling();
     577                        g.popClip(key);
     578
     579                        // Draw an outline for the crop selection box
     580                        g.drawRectangle(clip.getBounds(), 0.0, null, getPaintHighlightColor(), HIGHLIGHT_STROKE, null);
     581
     582                // otherwise, paint normally
    576583                } else {
    577                         paintImageTiling(g);
    578                 }
    579 
     584                        paintImageTiling();
     585                }
     586
     587                PolygonBounds poly = (PolygonBounds) getBounds();
     588               
    580589                if (hasVisibleBorder()) {
    581                         g.setColor(getPaintBorderColor());
    582                         Stroke borderStroke = new BasicStroke(getThickness(), CAP, JOIN);
    583                         g.setStroke(borderStroke);
    584                         g.drawPolygon(getPolygon());
     590                        Stroke borderStroke = new Stroke(getThickness(), DEFAULT_CAP, DEFAULT_JOIN);
     591                        g.drawPolygon(poly, null, null, 0.0, null, getPaintBorderColor(), borderStroke);
    585592                }
    586593
    587594                if (isHighlighted()) {
    588                         Stroke borderStroke = new BasicStroke(1, CAP, JOIN);
    589                         g.setStroke(borderStroke);
    590                         g.setColor(getHighlightColor());
    591                         g.drawPolygon(getPolygon());
    592                 }
    593                
    594                 //System.out.print("p_");       
    595         }
    596 
    597         @Override
    598         public Color getHighlightColor() {
    599                 if (_highlightColor.equals(getBorderColor()))
    600                         return ALTERNATE_HIGHLIGHT;
    601                 return _highlightColor;
    602         }
    603 
    604         @Override
    605         public int setHighlightColor() {
    606                 super.setHighlightColor();
    607 
    608                 return Item.DEFAULT_CURSOR;
    609         }
    610 
    611         protected Picture createPicture() {
    612                 return ItemUtils.CreatePicture((Text) _source.copy(), _imageObserver);
     595                        Stroke borderStroke = new Stroke(1, DEFAULT_CAP, DEFAULT_JOIN);
     596                        g.drawPolygon(poly, null, null, 0.0, null, getHighlightColor(), borderStroke);
     597                }
     598        }
     599
     600        @Override
     601        public Colour getHighlightColor()
     602        {
     603                if (_highlightColour.equals(getBorderColor())) return ALTERNATE_HIGHLIGHT;
     604                return _highlightColour;
     605        }
     606
     607        protected Picture createPicture()
     608        {
     609                return ItemUtils.CreatePicture((Text) _source.copy());
    613610        }
    614611
     
    617614                Picture p = createPicture();
    618615                p._image = _image;
    619                 p._mode = _mode;
     616                p._highlightMode = _highlightMode;
    620617                // Doing Duplicate item duplicates link mark which we dont want to do
    621618                // when in audience mode because the linkMark will be copied incorrectly
     
    632629                        int endX = Math.round(bottomRight.x / _scale + _start.x);
    633630                        int endY = Math.round(bottomRight.y / _scale + _start.y);
    634                         int width = _image.getWidth(null);
    635                         int height = _image.getHeight(null);
     631                        int width = _image.getWidth();
     632                        int height = _image.getHeight();
    636633                        // adjust our start and end if the user has dragged outside of the
    637634                        // shape
     
    663660
    664661                p.updateSource();
    665                 p.updatePolygon();
     662                p.invalidateBounds();
    666663
    667664                return p;
     
    678675        public void scaleCrop() {
    679676                // scale crop values to within image bounds
    680                 int iw = _image.getWidth(null);
    681                 int ih = _image.getHeight(null);
     677                int iw = _image.getWidth();
     678                int ih = _image.getHeight();
    682679                if(iw > 0 || ih > 0) {
    683680                        while(_start.x >= iw) {
     
    723720                        _scale = oldScale;
    724721                } else {
    725                         _source.translate(new Point2D.Float(FrameMouseActions.MouseX,
    726                                         FrameMouseActions.MouseY), multiplier);
     722                        _source.translate(EcosystemManager.getInputManager().getCursorPosition(), multiplier);
    727723                }
    728724                updateSource();
    729                 updatePolygon();
     725                invalidateBounds();
    730726                // Make sure items that are resized display the border
    731727                invalidateAll();
     
    753749                }
    754750               
    755                 return Toolkit.getDefaultToolkit().createImage(
    756                                 new FilteredImageSource(_image.getSource(),
    757                                                 new CropImageFilter(_start.x, _start.y,
    758                                                                 getUnscaledWidth(), getUnscaledHeight())));
     751                return Image.createImageAsCroppedCopy(_image, _start.x, _start.y, getUnscaledWidth(), getUnscaledHeight());
    759752        }
    760753
     
    771764         */
    772765        public boolean isCropped() {
    773                 return (_end.x != 0 && _end.x != _image.getWidth(null)) || (_end.y != 0 && _end.y != _image.getHeight(null)) || _start.y != 0 || _start.x != 0;
     766                return (_end.x != 0 && _end.x != _image.getWidth()) || (_end.y != 0 && _end.y != _image.getHeight()) || _start.y != 0 || _start.x != 0;
    774767        }
    775768
     
    779772                // (notably.bmp) hence, we try this first, then if it fails we try
    780773                // ImageIO
     774                /*
    781775                try {
    782776                        _image = new ImageIcon(_path).getImage();
     
    785779
    786780                // if ImageIcon failed to read the image
    787                 if (_image == null || _image.getWidth(null) <= 0) {
     781                if (_image == null || _image.getWidth() <= 0) {
    788782                        try {
    789783                                _image = ImageIO.read(new File(_path));
     
    795789                        }
    796790                }
     791*/
     792                _image = Image.getImage(_path);
    797793                return true;
    798794        }
     
    827823        @Override
    828824        public boolean getLinkMark() {
    829                 return !FrameGraphics.isAudienceMode() && _source.getLinkMark();
     825                return !DisplayController.isAudienceMode() && _source.getLinkMark();
    830826        }
    831827
     
    892888                // If the image is cropped add the position for the start and finish of
    893889                // the crop to the soure text
    894                 if (_start.x > 0 || _start.y > 0 || _end.x != _image.getWidth(null)
    895                                 || _end.y != _image.getHeight(null)) {
     890                if (_start.x > 0 || _start.y > 0 || _end.x != _image.getWidth()
     891                                || _end.y != _image.getHeight()) {
    896892                        newText.append(" ").append(_start.x).append(" ").append(_start.y);
    897893                        newText.append(" ").append(_end.x).append(" ").append(_end.y);
     
    912908
    913909        @Override
    914         public void translate(Point2D origin, double ratio) {
     910        public void translate(Point origin, double ratio) {
    915911                _scale *= ratio;
    916912                updateSource();
     
    919915
    920916        @Override
    921         public Rectangle[] getDrawingArea() {
    922 
    923                 Rectangle[] da = super.getDrawingArea();
     917        public AxisAlignedBoxBounds getDrawingArea() {
     918
     919                AxisAlignedBoxBounds da = super.getDrawingArea();
    924920
    925921                if (getLink() != null || hasAction()) {
    926                         Rectangle[] da2 = new Rectangle[da.length + 1];
    927                         System.arraycopy(da, 0, da2, 0, da.length);
    928                         da2[da.length] = getLinkPoly().getBounds();
    929                         da2[da.length].translate(getX() - LEFT_MARGIN, getY()
    930                                         + getLinkYOffset());
    931                         da2[da.length].width += 2;
    932                         da2[da.length].height += 2;
    933                         da = da2;
     922                        AxisAlignedBoxBounds linkBounds = AxisAlignedBoxBounds.getEnclosing(getLinkBounds());
     923                        linkBounds.getTopLeft().add(getX() - LEFT_MARGIN, getY() + getLinkYOffset());
     924                        linkBounds.getSize().width += 2;
     925                        linkBounds.getSize().height += 2;
     926                        da.combineWith(linkBounds);
    934927                }
    935928
     
    963956                _rotate = rotate;
    964957                updateSource();
    965                 updatePolygon();
     958                invalidateBounds();
    966959        }
    967960       
     
    970963        }
    971964
    972         public boolean MouseOverBackgroundPixel(int mouseX, int mouseY, Color bg_col)
    973         {
    974                 int[] pixels = new int[1];
    975                  
     965        public boolean MouseOverBackgroundPixel(int mouseX, int mouseY, Colour bg_col)
     966        {
    976967                int base_x = (_anchorLeft!=null) ? _anchorLeft : _source.getX();
    977968                int base_y = (_anchorTop!=null) ? _anchorTop : _source.getY();
     
    979970                int y = mouseY - base_y;
    980971               
    981                 // Consider making this a slightly larger area to check, say 3 x 3?
    982                 // Back op if all are the same sought after color?
    983                 PixelGrabber grabber = new PixelGrabber(_image, x,y, 1, 1, pixels, 0, 1);
    984                
    985                 // The following might be a better approach, as it sets the color model
    986                 // when getPixels() is called, however, it might return an int[] or byte[]
    987                 // array (handled as Object), as so some extra complexity would exist in
    988                 // handling the returned result
    989                
    990                 //PixelGrabber pg = new PixelGrabber(_image, mouseX, mouseY, 1, 1, true);
    991                
    992                 try {
    993                         grabber.grabPixels(0);
    994                 }
    995                 catch (Exception e) {
    996                         e.printStackTrace();
    997                 }
    998                
    999        
    1000                 int c = pixels[0];
    1001                 int c_red    = (c & 0x00ff0000) >> 16;
    1002                 int c_green  = (c & 0x0000ff00) >> 8;
    1003                 int c_blue   =  c & 0x000000ff;
    1004                
    1005                 int bg_red   = (bg_col!=null) ? bg_col.getRed()   : 0xff;
    1006                 int bg_green = (bg_col!=null) ? bg_col.getGreen() : 0xff;
    1007                 int bg_blue  = (bg_col!=null) ? bg_col.getBlue()  : 0xff;
     972                Colour c = _image.getPixel(x, y);
     973
     974                int c_red    = c.getRed255();
     975                int c_green  = c.getGreen255();
     976                int c_blue   = c.getBlue255();
     977               
     978                int bg_red   = (bg_col!=null) ? bg_col.getRed255()   : 0xff;
     979                int bg_green = (bg_col!=null) ? bg_col.getGreen255() : 0xff;
     980                int bg_blue  = (bg_col!=null) ? bg_col.getBlue255()  : 0xff;
    1008981               
    1009982                int red_diff   = Math.abs(c_red   - bg_red);
Note: See TracChangeset for help on using the changeset viewer.