我遇到一些问题在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是我迄今为止最大的尺寸)
答案 0 :(得分:1)
首先,为什么要制作缩放位图的副本?你不能像这样直接压缩缩放的位图:
final Bitmap scaledImage = Bitmap.createBitmap(bitmapData, 0, 0,
imgWidth, imgHeight, scale, false);
scaledImage.compress(Bitmap.CompressFormat.JPEG, 100, baos);
如果您可以避免复制,则可以避免获取OutOfMemoryError
。
即使您使用JPEG压缩选择95%的质量(使用自然物体的照片时),您也可以实现良好的压缩效果,并且质量会无法察觉。您应该尝试质量设置并自行检查。
答案 1 :(得分:0)
这是现在为我工作的完整课程。您使用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;
}
}