Распаковка Bitmap из Base64 и GZIP

В моем приложении я получаю изображение профиля для пользователя, а затем сохраняю его в сериализованном классе в виде строки.

Я делаю сжатие GZIP и Base64, используя приведенный ниже код, но я не могу сделать обратное, как вы видите в методе getProfilePicture() ниже:

private void saveBitmap(){
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    mBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
    byte[] byteArray = byteArrayOutputStream.toByteArray();
    String bitmapContent = "";
    try {
        bitmapContent = FileHelpers.compressAndBase64(byteArray);
        //later save it...
        } catch (IOException e) {
          e.printStackTrace();
          Log.e(TAG, "Error converting bitmap to gzip and base64");
         }
}


public static String compressAndBase64(byte[] byteArray)
        throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    GZIPOutputStream zos = new GZIPOutputStream(baos);
    zos.write(byteArray);
    zos.close();
    byte[] bytes = baos.toByteArray();
    return Base64.encodeToString(bytes, Base64.DEFAULT);
}

Теперь я хочу преобразовать его обратно в растровое изображение... но пока мне это не удалось.

Шаги декодируют строку из Base64 в массив байтов, затем распаковывают массив байтов и преобразуют в растровое изображение.

   public Bitmap getProfilePicture(){

        if(getProfilePhotoBase64() != null) {
            byte[] decoded = Base64.decode(mProfilePhotoBase64.getBytes(), Base64.DEFAULT);
            final int BUFFER_SIZE = 32;
            ByteArrayInputStream is = new ByteArrayInputStream(decoded);
            GZIPInputStream gis = null;
            try {
                gis = new GZIPInputStream(is, BUFFER_SIZE);
            } catch (IOException e) {
                e.printStackTrace();
            }
            StringBuilder string = new StringBuilder();
            byte[] data = new byte[BUFFER_SIZE];
            int bytesRead;
            try {
                while ((bytesRead = gis.read(data)) != -1) {
                    string.append(new String(data, 0, bytesRead));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                gis.close();
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            byte[] byteArray = string.toString().getBytes();
            Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0,byteArray.length);

            if(bitmap != null) {
                return bitmap;
            } else {
                return null;
            }
        }

        return null;
    }

Это сообщение об ошибке, которое я получаю, используя приведенный выше код:

--- SkImageDecoder::Factory returned null

Я могу сделать это довольно легко на PHP, но чертовски сложно заставить это работать на Java!

if(isset($_POST["photo"])) {

    $photoContent = $_POST["photo"];
    $photo = imap_base64 ($photoContent);
    $photo = gzdecode($photo);

    $filename = $_POST["username"].".png";

    $dir = SITE_ROOT_PATH."/images/".$user."/".$filename;
    file_force_contents($dir, $photo);

} else {
    $filename = "NO_PROFILE_PHOTO";
}

person Saeid Yazdani    schedule 01.07.2014    source источник


Ответы (2)


Хорошо, мне удалось решить проблему следующим образом:

/**
 * IMPORTANT NOTE!!!!!!!!!!!!!!
 * String is first converted to byte array, then compressed using GZIP and then
 * the resulting byte array is encoded to Base64.DEFAULT
 * @return
 */
public String getProfilePhotoBase64() {
    return mProfilePhotoBase64;
}

public Bitmap getProfilePicture(){
    if(getProfilePhotoBase64() != null) {
        byte[] decoded = Base64.decode(mProfilePhotoBase64.getBytes(), Base64.DEFAULT);

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ByteArrayInputStream bis = new ByteArrayInputStream(decoded);

        GZIPInputStream zis = null;
        try {
            zis = new GZIPInputStream(bis);
            byte[] tmpBuffer = new byte[256];
            int n;
            while ((n = zis.read(tmpBuffer)) >= 0) {
                bos.write(tmpBuffer, 0, n);
            }
            zis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        Bitmap bitmap = BitmapFactory.decodeByteArray(bos.toByteArray(), 0
                , bos.toByteArray().length);

        if(bitmap != null) {
            return bitmap;
        } else {
            return null;
        }
    }
    return null;
}
person Saeid Yazdani    schedule 02.07.2014
comment
Вы должны сказать, что вы изменили и почему. - person greenapps; 03.07.2014

А в чем именно проблема? CompressAndBase64() вернет пустую строку, так как boas.toByteArray() вернет 0 байтов, поскольку boas только что создан и, следовательно, пуст. Вам не нужно создавать удавов. Просто измените

return Base64.encodeToString(bytes, Base64.DEFAULT); 

to

return Base64.encodeToString(byteArray, Base64.DEFAULT);
person greenapps    schedule 01.07.2014
comment
boas.toByteArray() был объявлен ранее, поэтому он работает довольно хорошо, он сжимает растровое изображение и использует base64, но я не могу сделать обратное. Я могу распаковать base64 и gzip в php, так что код сжатия работает нормально. - person Saeid Yazdani; 01.07.2014
comment
Извини. Я следил за тем, чтобы вы заархивировали byteArray в удавы. Но если бы я использовал encodeToString для кодирования, я бы использовал decodeFromString для декодирования. Или используйте пару encode()/decode(). - person greenapps; 01.07.2014
comment
Такого метода нет (если это имеет значение) - person Saeid Yazdani; 01.07.2014
comment
Измените Base64.decode(mProfilePhotoBase64.getBytes(), на Base64.decode(mProfilePhotoBase64,. - person greenapps; 01.07.2014
comment
О, я вижу... Вы используете StringBuilder и обрабатываете байты своего изображения как строку. Ну, вы не можете этого сделать. Лучше поместить байты данных, прочитанные непосредственно в byteArray. - person greenapps; 01.07.2014