2014-08-27 1 views
0

Я создаю пользовательский UrlTileProvider для Google Maps API, который заботится о разрешении устройства:быстрый способ объединить изображения и преобразовывать их в массив байтов

  • если данные плитки 512x512px, просто возвращают плитка
  • если данные плитки 256x256px, объединить четыре плитки, соответствующие запрошенной плитки в следующий уровень масштабирования, чтобы вернуть 512x512px плитке

Как TileProvider в GoogleMaps' должен быть подан с Byte [], I необходимо уметь:

  • загрузить изображение и преобразовать его в байт [] - OK
  • загрузить четыре изображения, объединить их в одно целое, и преобразовать его в байт [] - KO

У меня есть рабочего решения с Android Bitmaps, но слияние + конверсия происходит очень медленно (около 1,5 секунд). Вот код:

public class CustomUrlTileProvider implements TileProvider { 

    // --------------------------------------------------------------------------------------- 
    // Private attributes : 

    private OnlineMapSource _source; 
    // --------------------------------------------------------------------------------------- 



    // --------------------------------------------------------------------------------------- 
    // Constructor : 

    public CustomUrlTileProvider(OnlineMapSource source) { 

     this._source = source; 
    } 

    @Override 
    public Tile getTile(int x, int y, int zoom) { 

     if(_source.getTileSize().getWidth() == 256 && _source.getTileSize().getHeight() == 256) { return getTileFromNextZoomLevel(x, y, zoom); } 
     else if(_source.getTileSize().getWidth() == 512 && _source.getTileSize().getHeight() == 512) { return getTileFromCurrentZoomLevel(x, y, zoom); } 
     else return TileProvider.NO_TILE; 
    } 
    // --------------------------------------------------------------------------------------- 



    // --------------------------------------------------------------------------------------- 
    // Tile creation : 

    public Tile getTileFromNextZoomLevel(int x, int y, int zoom) { 

     String topLeftTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2)).replace("{y}", "" + (y * 2)); 
     String topRightTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2 + 1)).replace("{y}", "" + (y * 2)); 
     String bottomLeftTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2)).replace("{y}", "" + (y * 2 + 1)); 
     String bottomRightTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2 + 1)).replace("{y}", "" + (y * 2 + 1)); 

     Bitmap topLeftTile = Utils.getBitmapFromURL(topLeftTileUrl); 
     Bitmap topRightTile = Utils.getBitmapFromURL(topRightTileUrl); 
     Bitmap bottomLeftTile = Utils.getBitmapFromURL(bottomLeftTileUrl); 
     Bitmap bottomRightTile = Utils.getBitmapFromURL(bottomRightTileUrl); 

     Bitmap[] parts = { 
      topLeftTile, 
      topRightTile, 
      bottomLeftTile, 
      bottomRightTile 
     }; 

     Bitmap tileBitmap = Bitmap.createBitmap(parts[0].getWidth() * 2, parts[0].getHeight() * 2, Bitmap.Config.ARGB_8888); 
     Canvas canvas = new Canvas(tileBitmap); 
     Paint paint = new Paint(); 
     for (int i = 0; i < parts.length; i++) { 
      canvas.drawBitmap(parts[i], parts[i].getWidth() * (i % 2), parts[i].getHeight() * (i/2), paint); 
     } 

     ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
     tileBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); 

     byte[] tile = stream.toByteArray(); 

     return tile == null ? TileProvider.NO_TILE : new Tile(_source.getTileSize().getWidth(), _source.getTileSize().getHeight(), tile); 
    } 

    public Tile getTileFromCurrentZoomLevel(int x, int y, int zoom) { 

     String tileUrl = _source.getUrlSchema().replace("{z}", "" + zoom).replace("{x}", "" + x).replace("{y}", "" + y); 

     byte[] tile = Utils.getByteArrayFromURL(tileUrl); 

     return tile == null ? TileProvider.NO_TILE : new Tile(_source.getTileSize().getWidth(), _source.getTileSize().getHeight(), tile); 
    } 
    // --------------------------------------------------------------------------------------- 
} 

Методы Utils.getBitmapFromURL и Utils.getByteArrayFromURL:

public static Bitmap getBitmapFromURL(String src) { 

    try { 
     URL url = new URL(src); 
     HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 
     connection.setDoInput(true); 
     connection.connect(); 
     InputStream input = connection.getInputStream(); 
     Bitmap myBitmap = BitmapFactory.decodeStream(input); 

     return myBitmap; 
    } 
    catch (IOException e) { return null; } 
} 

public static byte[] getByteArrayFromURL(String src) { 

    ByteArrayOutputStream bais = new ByteArrayOutputStream(); 
    InputStream is = null; 
    try { 

     is = new URL(src).openStream(); 
     byte[] byteChunk = new byte[4096]; 
     int n; 

     while ((n = is.read(byteChunk)) > 0) { 
      bais.write(byteChunk, 0, n); 
     } 
    } 
    catch (IOException e) { e.printStackTrace(); } 
    finally { 
     if (is != null) { 
      try { is.close(); } 
      catch (IOException e) { e.printStackTrace(); } 
     } 
    } 

    return bais.toByteArray(); 
} 

Так что вопрос: есть ли более быстрый способ достижения второй операции (скачать 4 изображения -> объединить их -> преобразовать результат в байт [])? Чтобы упростить, существует ли способ объединить четыре байта [] (представляющие изображения) в один?

EDIT: Я нашел, что время занимает не слияние, а преобразование Bitmap -> byte []. Поэтому я знаю, что пытаюсь использовать Bitmap.copyPixelsToBuffer вместо Bitmap.compress, без каких-либо успехов (без исключения, но без изображения). Есть идеи ?

Благодаря

ответ

0

Вполне вероятно, что большая часть затраченного времени тратится на получение плитки по сети. Если это так, то любой выигрыш в эффективности, который может быть достигнут благодаря более эффективному коду, будет иметь пропорционально небольшой эффект. Вы не можете ускорить работу сети через свой код.

+0

К сожалению, прошедшее время, которое я дал, является временем слияния + конвертирования. Время загрузки составляет около 300 мс, а слияние + конвертировать около 1,5 с. У меня есть лучшее решение для первой операции в чистой Java, я буду обновлять исходный пост. –