Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java	(revision 32020)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java	(revision 32021)
@@ -4,4 +4,6 @@
 import java.awt.Point;
 import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.HashMap;
 import java.util.List;
@@ -27,4 +29,5 @@
     protected String id;
     private final Map<String, String> noTileHeaders;
+    private final Map<String, String> noTileChecksums;
     private final Map<String, String> metadataHeaders;
     protected int tileSize;
@@ -44,4 +47,5 @@
         this.id = info.getUrl();
         this.noTileHeaders = info.getNoTileHeaders();
+        this.noTileChecksums = info.getNoTileChecksums();
         this.metadataHeaders = info.getMetadataHeaders();
         this.tileSize = info.getTileSize();
@@ -219,4 +223,28 @@
             }
         }
+        if (noTileChecksums != null) {
+            for (Entry<String, String> searchEntry: noTileChecksums.entrySet()) {
+                MessageDigest md = null;
+                try {
+                    md = MessageDigest.getInstance(searchEntry.getKey());
+                } catch (NoSuchAlgorithmException e) {
+                    break;
+                }
+                byte[] byteDigest = md.digest(content);
+                final int len = byteDigest.length;
+
+                char[] hexChars = new char[len * 2];
+                for (int i = 0, j = 0; i < len; i++) {
+                    final int v = byteDigest[i];
+                    int vn = (v & 0xf0) >> 4;
+                    hexChars[j++] = (char)(vn + (vn >= 10 ? 'a'-10 : '0'));
+                    vn = (v & 0xf);
+                    hexChars[j++] = (char)(vn + (vn >= 10 ? 'a'-10 : '0'));
+                }
+                if (new String(hexChars).equalsIgnoreCase(searchEntry.getValue())) {
+                    return true;
+                }
+            }
+        }
         return super.isNoTileAtZoom(headers, statusCode, content);
     }
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java	(revision 32020)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java	(revision 32021)
@@ -23,4 +23,7 @@
     /** headers meaning, that there is no tile at this zoom level */
     protected Map<String, String> noTileHeaders;
+
+    /** checksum of empty tiles */
+    protected Map<String, String> noTileChecksums;
 
     /** minimum zoom level supported by the tile source */
@@ -102,4 +105,13 @@
 
     /**
+     * Checkusm for empty tiles for servers delivering such tile types
+     * @return map of checksums, that when detected, means that this is "no tile at this zoom level" situation
+     * @since 32021
+     */
+    public Map<String, String> getNoTileChecksums() {
+        return noTileChecksums;
+    }
+
+    /**
      * Request supported minimum zoom level
      * @return minimum zoom level supported by tile source
