【问题标题】:Android - Upload an Image From DiskAndroid - 从磁盘上传图像
【发布时间】:2012-07-11 14:47:14
【问题描述】:

我在 Android 上上传文件时遇到了一些问题。我已经将应用程序的这一部分拼凑在一起,现在需要进行一些修改。

我正在尝试从 Uri 引用的磁盘映像将文件上传到服务器。

在上传之前,我正在尝试根据纵横比将图像缩小到 1280 的最大尺寸。

这是一个示例类,其中包含我正在使用的实际代码。我敢肯定它的效率非常低:

/**
 * This is a fake class, this is actually spread across 2 or 3 files
 */
public class Temp
{
  /**
   * This is used to return an Input stream of known size
   */
  public static class KnownSizeInputStream extends InputStreamBody
  {
    private int mLength;

    public KnownSizeInputStream( final InputStream in, final int length, final String mimeType, final String filename )
    {
      super( in, mimeType, filename );
      mLength = length;
    }

    public long getContentLength()
    {
      return mLength;
    }
  }

  private static final int MAX_WIDTH  = 1280;
  private static final int MAX_HEIGHT = 1280;

  /**
   * Open up a file on disk and convert it into a stream of known size
   */
  public KnownSizeInputStream toStreamAio( Context c, Uri path )
  {
    /**
     * Scale down bitmap
     */
    Bitmap bitmapData = null;

    try
    {
      bitmapData = BitmapFactory.decodeStream( c.getContentResolver().openInputStream( path ) );
    }
    catch( Exception e )
    {
      e.printStackTrace();
    }

    int imgWidth = bitmapData.getWidth();
    int imgHeight = bitmapData.getHeight();

    // Constrain to given size but keep aspect ratio
    float scaleFactor = Math.min( ( ( float )MAX_WIDTH ) / imgWidth, ( ( float )MAX_HEIGHT ) / imgHeight );

    Matrix scale = new Matrix();
    scale.postScale( scaleFactor, scaleFactor );
    final Bitmap scaledImage = Bitmap.createBitmap( bitmapData, 0, 0, imgWidth, imgHeight, scale, false );

    try
    {
      bitmapData = scaledImage.copy( scaledImage.getConfig(), true );

      scaledImage.recycle();
    }
    catch( Exception e )
    {
      e.printStackTrace();
    }

    /**
     * To byte[]
     */
    byte[] byteData = null;

    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    bitmapData.compress( Bitmap.CompressFormat.JPEG, 100, baos );

    byteData = baos.toByteArray();

    /**
     * To stream
     */
    return new KnownSizeInputStream( new ByteArrayInputStream( byteData ), byteData.length, "image/jpg", "Some image" );
  }

  /** 
   * Some pieces are removed, the main part is the addPart line
   */
  public void doUpload()
  {
    // create a new HttpPost, to our specified URI
    HttpPost post = new HttpPost( postUri );

    // org.apache.http.entity.mime
    MultipartEntity entity = new MultipartEntity( HttpMultipartMode.STRICT );


    // This line starts all of the issues
    entity.addPart( "file", toStreamAio( mContext, Uri.parse( "/some/file.jpg" ) ) );


    post.setEntity( entity );

    // send it
    HttpResponse response = client.execute( post );

  }
}

这是我得到的例外,我猜测调整大小试图分配图像的完整大小:

Caused by: java.lang.OutOfMemoryError
 at android.graphics.Bitmap.nativeCopy(Native Method)
 at android.graphics.Bitmap.copy(Bitmap.java:403)
 at com.app.helper.UploadableImage.toScaledBitmap(UploadableImage.java:170)
 at com.app.helper.UploadableImage.toByteArray(UploadableImage.java:53)
 at com.app.helper.UploadableImage.toStream(UploadableImage.java:242)
 at com.app.rest.task.UploadContentTask.doInBackground(UploadContentTask.java:80)
 at com.app.rest.task.UploadContentTask.doInBackground(UploadContentTask.java:1)
 at android.os.AsyncTask$2.call(AsyncTask.java:264)
 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
 ... 5 more

它被这条线触发了:

data = scaledImage.copy( scaledImage.getConfig(), true );

我想我要问的主要问题是,如何从磁盘上的路径获取图像,到缩放的图像,再到可以放入的流:

org.apache.http.entity.mime.MultipartEntity

通过:

.addPart("file", streamData);

最有效的方法是,假设图像可以很大(~6000px 是我迄今为止达到的最大尺寸)

【问题讨论】:

    标签: java android file-upload bitmap out-of-memory


    【解决方案1】:

    首先,为什么要复制缩放的位图?你不能像这样直接压缩缩放的位图吗:

    final Bitmap scaledImage = Bitmap.createBitmap(bitmapData, 0, 0,
            imgWidth, imgHeight, scale, false);
    scaledImage.compress(Bitmap.CompressFormat.JPEG, 100, baos);
    

    如果您可以避免复制,则可以避免获得OutOfMemoryError

    此外,即使您使用 JPEG 压缩选择 95% 的质量(在处理自然物体的照片时),您也可以实现良好的压缩,而质量损失几乎无法察觉。您应该尝试质量设置并自行检查。

    【讨论】:

      【解决方案2】:

      这是现在为我工作的完整课程。您使用 Context 和 Uri 加载它,然后调用三个公共方法中的任何一个:

      public class UploadableImage
      {
        private static final int MAX_WIDTH  = 1280;
        private static final int MAX_HEIGHT = 1280;
      
        private Uri              mUri;
      
        private String           mImageName;
      
        private Context          mContext;
      
        public UploadableImage( Context context )
        {
          mContext = context;
      
          generateFilename();
        }
      
        public UploadableImage( Context context, Uri uri )
        {
          mContext = context;
          mUri = uri;
      
          generateFilename();
        }
      
        // TODO Generate...
        private void generateFilename()
        {
          mImageName = UUID.randomUUID().toString() + ".jpg";
        }
      
        public void setUri( Uri uri )
        {
          mUri = uri;
        }
      
        public Bitmap toBitmap()
        {
          try
          {
            InputStream input = mContext.getContentResolver().openInputStream( mUri );
      
            BitmapFactory.Options readOptions = new BitmapFactory.Options();
            readOptions.inJustDecodeBounds = true;
      
            BitmapFactory.decodeStream( input, null, readOptions );
      
            input.close();
      
            // Raw height and width of image
            final int height = readOptions.outHeight;
            final int width = readOptions.outWidth;
      
            int inSampleSize = 1;
      
            if( height > MAX_HEIGHT || width > MAX_WIDTH )
            {
              if( width > height )
              {
                float result = ( float )height / ( float )MAX_HEIGHT;
      
                inSampleSize = ( int )FloatMath.ceil( result );
              }
              else
              {
                float result = ( float )width / ( float )MAX_WIDTH;
      
                inSampleSize = ( int )FloatMath.ceil( result );
              }
            }
      
            return toBitmap( inSampleSize );
          }
          catch( Exception e )
          {
            e.printStackTrace();
          }
      
          return null;
        }
      
        public Bitmap toBitmap( int sampleSize )
        {
          try
          {
            InputStream input = mContext.getContentResolver().openInputStream( mUri );
      
            input = mContext.getContentResolver().openInputStream( mUri );
      
            // Decode bitmap with inSampleSize set
            BitmapFactory.Options scaleOptions = new BitmapFactory.Options();
      
            scaleOptions.inJustDecodeBounds = false;
            scaleOptions.inSampleSize = sampleSize;
      
            Bitmap scaledBitmap = BitmapFactory.decodeStream( input, null, scaleOptions );
      
            input.close();
      
            return scaledBitmap;
          }
          catch( Exception e )
          {
            e.printStackTrace();
          }
      
          return null;
        }
      
        public KnownSizeInputStream toMimeStream()
        {
          Bitmap scaledBitmap = toBitmap();
      
          ByteArrayOutputStream stream = new ByteArrayOutputStream();
      
          scaledBitmap.compress( Bitmap.CompressFormat.JPEG, 95, stream );
      
          byte[] byteArray = stream.toByteArray();
      
          return new KnownSizeInputStream( new ByteArrayInputStream( byteArray ), byteArray.length, "image/jpg", mImageName );
        }
      
        public String toString()
        {
          return "UploadableImage, Uri: " + mUri;
        }
      }
      

      【讨论】:

        猜你喜欢
        • 2012-07-29
        • 2016-06-25
        • 1970-01-01
        • 2018-10-23
        • 2013-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多