Changeset 13220 in josm


Ignore:
Timestamp:
2017-12-18T00:46:58+01:00 (6 years ago)
Author:
Don-vip
Message:

see #15574:

  • additionally refactors ImageDisplay to use ImageEntry instead; stores width and height info while metadata of images are read; might break plugin code (patch by cmuelle8, minor changes)
  • remove double semicolon causing https://github.com/pmd/pmd/issues/785
  • enable PMD rule DoNotCallGarbageCollectionExplicitly
  • disable SpotBugs rule ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD
Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java

    r13206 r13220  
    8080import org.openstreetmap.josm.io.GpxReader;
    8181import org.openstreetmap.josm.spi.preferences.Config;
    82 import org.openstreetmap.josm.tools.ExifReader;
    8382import org.openstreetmap.josm.tools.GBC;
    8483import org.openstreetmap.josm.tools.ImageProvider;
     
    459458            imgList.getSelectionModel().addListSelectionListener(evt -> {
    460459                int index = imgList.getSelectedIndex();
    461                 Integer orientation = ExifReader.readOrientation(yLayer.data.get(index).getFile());
    462                 imgDisp.setImage(yLayer.data.get(index).getFile(), orientation);
     460                imgDisp.setImage(yLayer.data.get(index));
    463461                Date date = yLayer.data.get(index).getExifTime();
    464462                if (date != null) {
     
    483481                if (fc == null)
    484482                    return;
    485                 File sel = fc.getSelectedFile();
    486 
    487                 Integer orientation = ExifReader.readOrientation(sel);
    488                 imgDisp.setImage(sel, orientation);
    489 
    490                 Date date = ExifReader.readTime(sel);
     483                ImageEntry entry = new ImageEntry(fc.getSelectedFile());
     484                entry.extractExif();
     485                imgDisp.setImage(entry);
     486
     487                Date date = entry.getExifTime();
    491488                if (date != null) {
    492489                    lbExifTime.setText(DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM).format(date));
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java

    r13191 r13220  
    4646
    4747    /** The file that is currently displayed */
    48     private File file;
     48    private ImageEntry entry;
    4949
    5050    /** The image currently displayed */
     
    215215    private class LoadImageRunnable implements Runnable, ImageObserver {
    216216
     217        private final ImageEntry entry;
    217218        private final File file;
    218         private final int orientation;
    219         private int width;
    220         private int height;
    221 
    222         LoadImageRunnable(File file, Integer orientation) {
    223             this.file = file;
    224             this.orientation = orientation == null ? -1 : orientation;
     219
     220        LoadImageRunnable(ImageEntry entry) {
     221            this.entry = entry;
     222            this.file = entry.getFile();
    225223        }
    226224
     
    229227            if (((infoflags & ImageObserver.WIDTH) == ImageObserver.WIDTH) &&
    230228                ((infoflags & ImageObserver.HEIGHT) == ImageObserver.HEIGHT)) {
    231                 this.width = width;
    232                 this.height = height;
    233                 synchronized (this) {
    234                     this.notify();
     229                synchronized (entry) {
     230                    entry.setWidth(width);
     231                    entry.setHeight(height);
     232                    entry.notifyAll();
    235233                    return false;
    236234                }
    237235            }
    238236            return true;
     237        }
     238
     239        private boolean updateImageEntry(Image img) {
     240            if (!(entry.getWidth() > 0 && entry.getHeight() > 0)) {
     241                synchronized (entry) {
     242                    img.getWidth(this);
     243                    img.getHeight(this);
     244
     245                    long now = System.currentTimeMillis();
     246                    while (!(entry.getWidth() > 0 && entry.getHeight() > 0)) {
     247                        try {
     248                            entry.wait(1000);
     249                            if (this.entry != ImageDisplay.this.entry)
     250                                return false;
     251                            if (System.currentTimeMillis() - now > 10000)
     252                                synchronized (ImageDisplay.this) {
     253                                    errorLoading = true;
     254                                    ImageDisplay.this.repaint();
     255                                    return false;
     256                                }
     257                        } catch (InterruptedException e) {
     258                            Logging.trace(e);
     259                            Logging.warn("InterruptedException in {0} while getting properties of image {1}",
     260                                    getClass().getSimpleName(), file.getPath());
     261                            Thread.currentThread().interrupt();
     262                        }
     263                    }
     264                }
     265            }
     266            return true;
     267        }
     268
     269        private boolean mayFitMemory(long amountWanted) {
     270            return amountWanted < (
     271                   Runtime.getRuntime().maxMemory() -
     272                   Runtime.getRuntime().totalMemory() +
     273                   Runtime.getRuntime().freeMemory());
    239274        }
    240275
     
    242277        public void run() {
    243278            Image img = Toolkit.getDefaultToolkit().createImage(file.getPath());
    244 
    245             synchronized (this) {
    246                 width = -1;
    247                 img.getWidth(this);
    248                 img.getHeight(this);
    249 
    250                 while (width < 0) {
    251                     try {
    252                         this.wait();
    253                         if (width < 0) {
    254                             errorLoading = true;
    255                             return;
    256                         }
    257                     } catch (InterruptedException e) {
    258                         e.printStackTrace();
    259                     }
    260                 }
    261             }
    262 
    263             long allocatedMem = Runtime.getRuntime().totalMemory() -
    264                     Runtime.getRuntime().freeMemory();
    265             long mem = Runtime.getRuntime().maxMemory()-allocatedMem;
    266 
    267             if (mem > ((long) width*height*4)*2) {
     279            if (!updateImageEntry(img))
     280                return;
     281
     282            int width = entry.getWidth();
     283            int height = entry.getHeight();
     284
     285            if (mayFitMemory(((long) width)*height*4*2)) {
    268286                Logging.info("Loading {0} using default toolkit", file.getPath());
    269287                tracker.addImage(img, 1);
     
    271289                // Wait for the end of loading
    272290                while (!tracker.checkID(1, true)) {
    273                     if (this.file != ImageDisplay.this.file) {
     291                    if (this.entry != ImageDisplay.this.entry) {
    274292                        // The file has changed
    275293                        tracker.removeImage(img);
     
    280298                    } catch (InterruptedException e) {
    281299                        Logging.trace(e);
    282                         Logging.warn("InterruptedException in "+getClass().getSimpleName()+
    283                                 " while loading image "+file.getPath());
     300                        Logging.warn("InterruptedException in {0} while loading image {1}",
     301                                getClass().getSimpleName(), file.getPath());
    284302                        Thread.currentThread().interrupt();
    285303                    }
    286304                }
    287305                if (tracker.isErrorID(1)) {
     306                    // the tracker catches OutOfMemory conditions
    288307                    img = null;
    289                     System.gc();
    290308                }
    291309            } else {
     
    293311            }
    294312
    295             if (img == null || width <= 0 || height <= 0) {
    296                 tracker.removeImage(img);
    297                 img = null;
    298             }
    299 
    300313            synchronized (ImageDisplay.this) {
    301                 if (this.file != ImageDisplay.this.file) {
     314                if (this.entry != ImageDisplay.this.entry) {
    302315                    // The file has changed
    303316                    tracker.removeImage(img);
     
    307320                if (img != null) {
    308321                    boolean switchedDim = false;
    309                     if (ExifReader.orientationNeedsCorrection(orientation)) {
    310                         if (ExifReader.orientationSwitchesDimensions(orientation)) {
     322                    if (ExifReader.orientationNeedsCorrection(entry.getExifOrientation())) {
     323                        if (ExifReader.orientationSwitchesDimensions(entry.getExifOrientation())) {
    311324                            width = img.getHeight(null);
    312325                            height = img.getWidth(null);
     
    314327                        }
    315328                        final BufferedImage rot = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    316                         final AffineTransform xform = ExifReader.getRestoreOrientationTransform(orientation,
    317                                 img.getWidth(null), img.getHeight(null));
     329                        final AffineTransform xform = ExifReader.getRestoreOrientationTransform(
     330                                entry.getExifOrientation(),
     331                                img.getWidth(null),
     332                                img.getHeight(null));
    318333                        final Graphics2D g = rot.createGraphics();
    319334                        g.drawImage(img, xform, null);
     
    326341                    visibleRect = new VisRect(0, 0, width, height);
    327342
    328                     Logging.info("Loaded {0} with dimensions {1}x{2} mem(prev-avail={3}m,taken={4}m) exifOrientationSwitchedDimension={5}",
    329                             file.getPath(), width, height, mem/1024/1024, width*height*4/1024/1024, switchedDim);
     343                    Logging.info("Loaded {0} with dimensions {1}x{2} memoryTaken={3}m exifOrientationSwitchedDimension={4}",
     344                            file.getPath(), width, height, width*height*4/1024/1024, switchedDim);
    330345                }
    331346
     
    361376
    362377        private void mouseWheelMovedImpl(int x, int y, int rotation, boolean refreshMousePointInImg) {
    363             File file;
     378            ImageEntry entry;
    364379            Image image;
    365380            VisRect visibleRect;
    366381
    367382            synchronized (ImageDisplay.this) {
    368                 file = ImageDisplay.this.file;
     383                entry = ImageDisplay.this.entry;
    369384                image = ImageDisplay.this.image;
    370385                visibleRect = ImageDisplay.this.visibleRect;
     
    418433
    419434            synchronized (ImageDisplay.this) {
    420                 if (ImageDisplay.this.file == file) {
     435                if (ImageDisplay.this.entry == entry) {
    421436                    ImageDisplay.this.visibleRect = visibleRect;
    422437                }
     
    447462        public void mouseClicked(MouseEvent e) {
    448463            // Move the center to the clicked point.
    449             File file;
     464            ImageEntry entry;
    450465            Image image;
    451466            VisRect visibleRect;
    452467
    453468            synchronized (ImageDisplay.this) {
    454                 file = ImageDisplay.this.file;
     469                entry = ImageDisplay.this.entry;
    455470                image = ImageDisplay.this.image;
    456471                visibleRect = ImageDisplay.this.visibleRect;
     
    486501
    487502            synchronized (ImageDisplay.this) {
    488                 if (ImageDisplay.this.file == file) {
     503                if (ImageDisplay.this.entry == entry) {
    489504                    ImageDisplay.this.visibleRect = visibleRect;
    490505                }
     
    519534                return;
    520535
    521             File file;
     536            ImageEntry entry;
    522537            Image image;
    523538            VisRect visibleRect;
    524539
    525540            synchronized (ImageDisplay.this) {
    526                 file = ImageDisplay.this.file;
     541                entry = ImageDisplay.this.entry;
    527542                image = ImageDisplay.this.image;
    528543                visibleRect = ImageDisplay.this.visibleRect;
     
    539554                visibleRect.checkRectPos();
    540555                synchronized (ImageDisplay.this) {
    541                     if (ImageDisplay.this.file == file) {
     556                    if (ImageDisplay.this.entry == entry) {
    542557                        ImageDisplay.this.visibleRect = visibleRect;
    543558                    }
     
    565580        @Override
    566581        public void mouseReleased(MouseEvent e) {
    567             File file;
     582            ImageEntry entry;
    568583            Image image;
     584            VisRect visibleRect;
    569585
    570586            synchronized (ImageDisplay.this) {
    571                 file = ImageDisplay.this.file;
     587                entry = ImageDisplay.this.entry;
    572588                image = ImageDisplay.this.image;
     589                visibleRect = ImageDisplay.this.visibleRect;
    573590            }
    574591
     
    614631
    615632            synchronized (ImageDisplay.this) {
    616                 if (file == ImageDisplay.this.file) {
     633                if (entry == ImageDisplay.this.entry) {
    617634                    if (selectedRect == null) {
    618635                        ImageDisplay.this.visibleRect = visibleRect;
     
    656673    /**
    657674     * Sets a new source image to be displayed by this {@code ImageDisplay}.
    658      * @param file new source image
    659      * @param orientation orientation of new source (landscape, portrait, upside-down, etc.)
     675     * @param entry new source image
     676     * @since 13220
    660677     */
    661     public void setImage(File file, Integer orientation) {
     678    public void setImage(ImageEntry entry) {
    662679        synchronized (this) {
    663             this.file = file;
     680            this.entry = entry;
    664681            image = null;
    665682            errorLoading = false;
    666683        }
    667684        repaint();
    668         if (file != null) {
    669             new Thread(new LoadImageRunnable(file, orientation), LoadImageRunnable.class.getName()).start();
     685        if (entry != null) {
     686            new Thread(new LoadImageRunnable(entry), LoadImageRunnable.class.getName()).start();
    670687        }
    671688    }
     
    682699    @Override
    683700    public void paintComponent(Graphics g) {
     701        ImageEntry entry;
    684702        Image image;
    685         File file;
    686703        VisRect visibleRect;
    687704        boolean errorLoading;
     
    689706        synchronized (this) {
    690707            image = this.image;
    691             file = this.file;
     708            entry = this.entry;
    692709            visibleRect = this.visibleRect;
    693710            errorLoading = this.errorLoading;
     
    699716
    700717        Dimension size = getSize();
    701         if (file == null) {
     718        if (entry == null) {
    702719            g.setColor(Color.black);
    703720            String noImageStr = tr("No image");
     
    710727            String loadingStr;
    711728            if (!errorLoading) {
    712                 loadingStr = tr("Loading {0}", file.getName());
     729                loadingStr = tr("Loading {0}", entry.getFile().getName());
    713730            } else {
    714                 loadingStr = tr("Error on file {0}", file.getName());
     731                loadingStr = tr("Error on file {0}", entry.getFile().getName());
    715732            }
    716733            Rectangle2D noImageSize = g.getFontMetrics(g.getFont()).getStringBounds(loadingStr, g);
     
    742759                    r.x = visibleRect.x;
    743760                    r.y = visibleRect.y;
    744                     System.gc();
    745761                }
    746762            } else {
     
    772788            }
    773789            if (errorLoading) {
    774                 String loadingStr = tr("Error on file {0}", file.getName());
     790                String loadingStr = tr("Error on file {0}", entry.getFile().getName());
    775791                Rectangle2D noImageSize = g.getFontMetrics(g.getFont()).getStringBounds(loadingStr, g);
    776792                g.drawString(loadingStr,
     
    885901     */
    886902    public void zoomBestFitOrOne() {
    887         File file;
     903        ImageEntry entry;
    888904        Image image;
    889905        VisRect visibleRect;
    890906
    891907        synchronized (this) {
    892             file = this.file;
     908            entry = this.entry;
    893909            image = this.image;
    894910            visibleRect = this.visibleRect;
     
    911927
    912928        synchronized (this) {
    913             if (file == this.file) {
     929            if (this.entry == entry) {
    914930                this.visibleRect = visibleRect;
    915931            }
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java

    r13060 r13220  
    2121import com.drew.metadata.exif.ExifIFD0Directory;
    2222import com.drew.metadata.exif.GpsDirectory;
     23import com.drew.metadata.jpeg.JpegDirectory;
    2324
    2425/**
     
    5354    private Date gpsTime;
    5455
     56    private int width;
     57    private int height;
     58
    5559    /**
    5660     * When the correlation dialog is open, we like to show the image position
     
    7781
    7882    /**
     83     * Returns width of the image this ImageEntry represents.
     84     * @return width of the image this ImageEntry represents
     85     * @since 13220
     86     */
     87    public int getWidth() {
     88        return width;
     89    }
     90
     91    /**
     92     * Returns height of the image this ImageEntry represents.
     93     * @return height of the image this ImageEntry represents
     94     * @since 13220
     95     */
     96    public int getHeight() {
     97        return height;
     98    }
     99
     100    /**
    79101     * Returns the position value. The position value from the temporary copy
    80102     * is returned if that copy exists.
     
    142164     */
    143165    public Integer getExifOrientation() {
    144         return exifOrientation;
     166        return exifOrientation != null ? exifOrientation : 1;
    145167    }
    146168
     
    228250            new ThumbsLoader(Collections.singleton(this)).run();
    229251        }
     252    }
     253
     254    /**
     255     * Sets the width of this ImageEntry.
     256     * @param width set the width of this ImageEntry
     257     * @since 13220
     258     */
     259    public void setWidth(int width) {
     260        this.width = width;
     261    }
     262
     263    /**
     264     * Sets the height of this ImageEntry.
     265     * @param height set the height of this ImageEntry
     266     * @since 13220
     267     */
     268    public void setHeight(int height) {
     269        this.height = height;
    230270    }
    231271
     
    457497        }
    458498
     499        final Directory dir = metadata.getFirstDirectoryOfType(JpegDirectory.class);
    459500        final Directory dirExif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
    460501        final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     
    464505                int orientation = dirExif.getInt(ExifIFD0Directory.TAG_ORIENTATION);
    465506                setExifOrientation(orientation);
     507            }
     508        } catch (MetadataException ex) {
     509            Logging.debug(ex);
     510        }
     511
     512        try {
     513            if (dir != null) {
     514                // there are cases where these do not match width and height stored in dirExif
     515                int width = dir.getInt(JpegDirectory.TAG_IMAGE_WIDTH);
     516                int height = dir.getInt(JpegDirectory.TAG_IMAGE_HEIGHT);
     517                setWidth(width);
     518                setHeight(height);
    466519            }
    467520        } catch (MetadataException ex) {
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java

    r13130 r13220  
    323323                // Set only if the image is new to preserve zoom and position if the same image is redisplayed
    324324                // (e.g. to update the OSD).
    325                 imgDisplay.setImage(entry.getFile(), entry.getExifOrientation());
     325                imgDisplay.setImage(entry);
    326326            }
    327327            setTitle(tr("Geotagged Images") + (entry.getFile() != null ? " - " + entry.getFile().getName() : ""));
     
    356356            // do not actually show the dialog again with a blank image if currently hidden (fix #10672)
    357357            setTitle(tr("Geotagged Images"));
    358             imgDisplay.setImage(null, null);
     358            imgDisplay.setImage(null);
    359359            imgDisplay.setOsdText("");
    360360            return;
  • trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java

    r11384 r13220  
    100100         * A set of values that were used for this key.
    101101         */
    102         public final SortedSet<String> values = new TreeSet<>();; // NOSONAR
     102        public final SortedSet<String> values = new TreeSet<>(); // NOSONAR
    103103        private boolean hadKeys;
    104104        private boolean hadEmpty;
  • trunk/tools/pmd/josm-ruleset.xml

    r13207 r13220  
    157157    <exclude name="ConstructorCallsOverridableMethod"/>
    158158    <exclude name="DataflowAnomalyAnalysis"/>
    159     <exclude name="DoNotCallGarbageCollectionExplicitly"/>
    160159    <exclude name="DoNotCallSystemExit"/>
    161160    <exclude name="DontImportSun"/>
  • trunk/tools/spotbugs/josm-filter.xml

    r12277 r13220  
    11<FindBugsFilter>
    22
    3         <Match>
    4                 <Bug pattern="DM_EXIT" />
    5         </Match>
    6         <Match>
    7                 <Bug pattern="DMI_HARDCODED_ABSOLUTE_FILENAME" />
    8         </Match>
    9         <Match>
    10                 <Bug pattern="EQ_DOESNT_OVERRIDE_EQUALS" />
    11         </Match>
    12         <Match>
    13                 <Bug pattern="IL_INFINITE_LOOP" />
    14         </Match>
    15         <Match>
    16                 <Bug pattern="NM_CONFUSING" />
    17         </Match>
    18         <Match>
    19                 <Bug pattern="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE" />
    20         </Match>
    21         <Match>
    22                 <Bug pattern="SE_BAD_FIELD" />
    23         </Match>
    24         <Match>
    25                 <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED" />
    26         </Match>
    27         <Match>
    28                 <Bug pattern="UI_INHERITANCE_UNSAFE_GETRESOURCE" />
    29         </Match>
    30         <Match>
    31                 <Bug pattern="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" />
    32         </Match>
     3    <Match>
     4        <Bug pattern="DM_EXIT" />
     5    </Match>
     6    <Match>
     7        <Bug pattern="DMI_HARDCODED_ABSOLUTE_FILENAME" />
     8    </Match>
     9    <Match>
     10        <Bug pattern="EQ_DOESNT_OVERRIDE_EQUALS" />
     11    </Match>
     12    <Match>
     13        <Bug pattern="IL_INFINITE_LOOP" />
     14    </Match>
     15    <Match>
     16        <Bug pattern="NM_CONFUSING" />
     17    </Match>
     18    <Match>
     19        <Bug pattern="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE" />
     20    </Match>
     21    <Match>
     22        <Bug pattern="SE_BAD_FIELD" />
     23    </Match>
     24    <Match>
     25        <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED" />
     26    </Match>
     27    <Match>
     28        <Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" />
     29    </Match>
     30    <Match>
     31        <Bug pattern="UI_INHERITANCE_UNSAFE_GETRESOURCE" />
     32    </Match>
     33    <Match>
     34        <Bug pattern="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" />
     35    </Match>
    3336
    34         <Match>
    35                 <Bug pattern="EI_EXPOSE_REP2" />
    36                 <Class name="org.openstreetmap.josm.tools.CopyList" />
    37         </Match>
    38         <Match>
    39                 <Bug pattern="MS_CANNOT_BE_FINAL" />
    40                 <Class name="org.openstreetmap.josm.Main" />
    41         </Match>
    42         <Match>
    43                 <Bug pattern="MS_SHOULD_BE_FINAL" />
    44                 <Class name="org.openstreetmap.josm.Main" />
    45         </Match>
     37    <Match>
     38        <Bug pattern="EI_EXPOSE_REP2" />
     39        <Class name="org.openstreetmap.josm.tools.CopyList" />
     40    </Match>
     41    <Match>
     42        <Bug pattern="MS_CANNOT_BE_FINAL" />
     43        <Class name="org.openstreetmap.josm.Main" />
     44    </Match>
     45    <Match>
     46        <Bug pattern="MS_SHOULD_BE_FINAL" />
     47        <Class name="org.openstreetmap.josm.Main" />
     48    </Match>
    4649
    47         <Match>
    48                 <Class name="~com.*" />
    49         </Match>
     50    <Match>
     51        <Class name="~com.*" />
     52    </Match>
    5053    <Match>
    5154        <Class name="~gnu.getopt.*" />
     
    5457        <Class name="~javax.json.*" />
    5558    </Match>
    56         <Match>
    57                 <Class name="~oauth.signpost.*" />
    58         </Match>
    59         <Match>
    60                 <Class name="~org.apache.*" />
    61         </Match>
     59    <Match>
     60        <Class name="~oauth.signpost.*" />
     61    </Match>
     62    <Match>
     63        <Class name="~org.apache.*" />
     64    </Match>
    6265    <Match>
    6366        <Class name="~org.glassfish.json.*" />
    6467    </Match>
    65         <Match>
    66                 <Class name="~org.jdesktop.swinghelper.debug.*" />
    67         </Match>
    68         <Match>
    69                 <Class name="~org.openstreetmap.gui.jmapviewer.*" />
    70         </Match>
     68    <Match>
     69        <Class name="~org.jdesktop.swinghelper.debug.*" />
     70    </Match>
     71    <Match>
     72        <Class name="~org.openstreetmap.gui.jmapviewer.*" />
     73    </Match>
    7174    <Match>
    7275        <Class name="~org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.*" />
Note: See TracChangeset for help on using the changeset viewer.