Related
In CameraX Analysis, setTargetResolution(new Size(2560, 800), but in Analyzer imageProxy.getImage.getWidth=1280 and getHeight=400, and YUVToByte(imageProxy.getImage).length()=768000。In Camera, parameter.setPreviewSize(2560, 800) then byte[].length in onPreviewFrame is 3072000(equales 768000*(2560/1280)*(800/400))。How can I make CameraX Analyzer imageProxy.getImage.getWidth and getHeight = 2560 and 800, and YUVToByte(ImageProxy.getImage).length()=3072000? In CameraX onPreviewFrame(), res always = null, in Camera onPreviewFrame(), res can get currect value, what's the different between CameraX and Camera? And what should I do in CameraX?
CameraX:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
try {
copyDataBase();
} catch (IOException e) {
e.printStackTrace();
}
getSupportActionBar().hide();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
viewFinder = findViewById(R.id.previewView);
executor = Executors.newSingleThreadExecutor();
if (!allPermissionGranted()) {
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
}
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
width = metric.widthPixels;
height = metric.heightPixels;
l = 100;
r = width - 100;
ntmpH = (r - l) * 58 / 100;
t = (height - ntmpH) / 2;
b = t + ntmpH;
double proportion = (double) width / (double) preHeight;
double hproportion = (double) height / (double) preWidth;
l = (int) (l / proportion);
t = (int) (t / hproportion);
r = (int) (r / proportion);
b = (int) (b / hproportion);
m_ROI[0] = l;
m_ROI[1] = t;
m_ROI[2] = r;
m_ROI[3] = b;
cameraProviderFuture = processCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
#SuppressLint("RestrictedApi") Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder().
requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setTargetResolution(new Size(2560, 800))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.setTargetRotation(Surface.ROTATION_90)
.build();
imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
#SuppressLint("UnsafeExperimentalUsageError")
#Override
public void analyze(#NonNull ImageProxy imageProxy) {
if (imageProxy.getFormat() == ImageFormat.YUV_420_888) {
image = imageProxy.getImage();
bIninKernal();
Log.d("Size ", image.getWidth() + "/" + image.getHeight());
onPreviewFrame(YUVToByte(image));
} else {
Log.d("Status ", "照片格式錯誤" + imageProxy.getFormat());
}
imageProxy.close();
}
});
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);
preview.setSurfaceProvider(viewFinder.createSurfaceProvider());
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}, ContextCompat.getMainExecutor(this));
}
#NonNull
#Override
public CameraXConfig getCameraXConfig() {
return Camera2Config.defaultConfig();
}
private boolean allPermissionGranted() {
for (String permission : REQUIRED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
private byte[] YUVToByte(Image image) {
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer0 = planes[0].getBuffer();
ByteBuffer buffer1 = planes[1].getBuffer();
ByteBuffer buffer2 = planes[2].getBuffer();
int width = image.getWidth();
int height = image.getHeight();
byte[] data = new byte[image.getWidth() * image.getHeight() * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];
byte[] rowData1 = new byte[planes[1].getRowStride()];
byte[] rowData2 = new byte[planes[2].getRowStride()];
int bytesPerPixel = ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8;
// loop via rows of u/v channels
int offsetY = 0;
int sizeY = width * height * bytesPerPixel;
int sizeUV = (width * height * bytesPerPixel) / 4;
for (int row = 0; row < height; row++) {
// fill data for Y channel, two row
{
int length = bytesPerPixel * width;
buffer0.get(data, offsetY, length);
if (height - row != 1)
buffer0.position(buffer0.position() + planes[0].getRowStride() - length);
offsetY += length;
}
if (row >= height / 2)
continue;
{
int uvlength = planes[1].getRowStride();
if ((height / 2 - row) == 1) {
uvlength = width / 2 - planes[1].getPixelStride() + 1;
}
buffer1.get(rowData1, 0, uvlength);
buffer2.get(rowData2, 0, uvlength);
// fill data for u/v channels
for (int col = 0; col < width / 2; ++col) {
// u channel
data[sizeY + (row * width) / 2 + col] = rowData1[col * planes[1].getPixelStride()];
// v channel
data[sizeY + sizeUV + (row * width) / 2 + col] = rowData2[col * planes[2].getPixelStride()];
}
}
}
return data;
}
private void bIninKernal() {
api = new LPR();
String FilePath = Environment.getExternalStorageDirectory().toString() + "/lpr.key";
int nRet = api.Init(this, m_ROI[0], m_ROI[1], m_ROI[2], m_ROI[3], preHeight, preWidth, FilePath);
if (nRet != 0) {
bInitKernal = false;
Log.d("Status ", "相機開啟失敗");
} else {
bInitKernal = true;
}
}
private void onPreviewFrame(byte[] data) {
bIninKernal();
tackData = data;
Log.d("data length ", data.length + "");
resultStr = "";
if (!leaving && bInitKernal) {
byte[] result;
String res = "";
result = api.VideoRec(tackData, 1280, 400, 1);
try {
res = new String(result, "gb2312");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (res != null && !"".equals(res.trim())) {
resultStr = res.trim();
if (resultStr != "") {
leaving = true;
MediaActionSound sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
Log.d("Status ", "辨識成功");
Log.d("車牌號碼", resultStr);
Thread thread = new Thread(Image_update);
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent intent = new Intent(MainActivity2.this, MainActivity.class);
intent.putExtra("result", resultStr);
Log.d("result", resultStr);
setResult(1, intent);
finish();
}
} else {
Log.d("Status ", "未分辨車牌號碼,請重拍");
}
}
}
public void copyDataBase() throws IOException {
// Common common = new Common();
// 取得SK卡路徑/lpr.key
String dst = Environment.getExternalStorageDirectory().toString() + "/lpr.key";
File file = new File(dst);
if (!file.exists()) {
// file.createNewFile();
} else {
file.delete();
}
Log.d("File Name", file.toString());
try {
InputStream myInput = getAssets().open("lpr.key");
OutputStream myOutput = new FileOutputStream(dst);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch (Exception e) {
System.out.println("lpr.key" + "is not found");
}
}
private Runnable Image_update = new Runnable() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://0d9dccd7eac8.ngrok.io/")
.addConverterFactory(GsonConverterFactory.create())
.build();
MyAPIService myAPIService = retrofit.create(MyAPIService.class);
#Override
public void run() {
Log.d("Status ", "run");
Log.d("resultStr ", resultStr);
String url = "D:\\Images\\license_plate\\";
String imgStr = bitmap2base64(toBitmap(image));
LicensePlate licensePlate = new LicensePlate();
licensePlate.setsPlate(resultStr);
licensePlate.setsPicPosition(url + resultStr);
licensePlate.setImgStr(imgStr);
Call<LicensePlate> call = myAPIService.uploadLicensePlate(licensePlate);
call.enqueue(new Callback<LicensePlate>() {
#Override
public void onResponse(Call<LicensePlate> call, Response<LicensePlate> response) {
if(response.isSuccessful()){
Log.d("Status ", "照片上傳成功");
}else{
Log.d("Status ", "照片上傳失敗");
Log.d("response code ", response.code() + "");
}
}
#Override
public void onFailure(Call<LicensePlate> call, Throwable t) {
Log.d("Status ", "onFailure");
Log.d("Message ", t.getMessage());
}
});
}
};
private String bitmap2base64(Bitmap bitmap){
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT).trim().replaceAll("\n", "").replaceAll("\r", "");
}
private Bitmap toBitmap(Image image) {
Image.Plane[] planes = image.getPlanes();
ByteBuffer yBuffer = planes[0].getBuffer();
ByteBuffer uBuffer = planes[1].getBuffer();
ByteBuffer vBuffer = planes[2].getBuffer();
int ySize = yBuffer.remaining();
int uSize = uBuffer.remaining();
int vSize = vBuffer.remaining();
byte[] nv21 = new byte[ySize + uSize + vSize];
//U and V are swapped
yBuffer.get(nv21, 0, ySize);
vBuffer.get(nv21, ySize, vSize);
uBuffer.get(nv21, ySize + vSize, uSize);
YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 75, out);
byte[] imageBytes = out.toByteArray();
return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
}
}
Camera
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 隐藏标题
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int metricwidth = metric.widthPixels; // 屏幕宽度(像素)
int metricheight = metric.heightPixels; // 屏幕高度(像素)
try {
copyDataBase();
} catch (IOException e) {
e.printStackTrace();
}
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);// 竖屏
Configuration cf= this.getResources().getConfiguration(); //获取设置的配置信息
int noriention=cf.orientation;
requestWindowFeature(Window.FEATURE_NO_TITLE);// 隐藏标题
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
// // 屏幕常亮
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_lpr2);
findView();
}
private void findView() {
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
re_c = (RelativeLayout) findViewById(R.id.re_c);
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
width = metric.widthPixels; // 屏幕宽度(像素)
height = metric.heightPixels; // 屏幕高度(像素)
if(myView==null)
{
if (isFatty)
{
myView = new LPRfinderView2(LPR2Activity.this, width, height, isFatty);
}
else
{
myView = new LPRfinderView2(LPR2Activity.this, width, height);
}
re_c.addView(myView);
}
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(LPR2Activity.this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.setFocusable(true);
//surfaceView.invali.date();
}
public void copyDataBase() throws IOException {
// Common common = new Common();
// 取得SK卡路徑/lpr.key
String dst = Environment.getExternalStorageDirectory().toString() + "/lpr.key";
File file = new File(dst);
if (!file.exists()) {
// file.createNewFile();
} else {
file.delete();
}
Log.d("File Name", file.toString());
try {
InputStream myInput = getAssets().open("lpr.key");
OutputStream myOutput = new FileOutputStream(dst);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch (Exception e) {
System.out.println("lpr.key" + "is not found");
}
}
public void surfaceCreated(SurfaceHolder holder) {
if (mycamera == null) {
try {
mycamera = Camera.open();
} catch (Exception e) {
e.printStackTrace();
String mess = "打开摄像头失败";
Toast.makeText(getApplicationContext(), mess, Toast.LENGTH_LONG).show();
return;
}
}
if(mycamera!=null)
{
try {
mycamera.setPreviewDisplay(holder);
timer2 = new Timer();
if (timer == null)
{
timer = new TimerTask()
{
public void run()
{
if (mycamera != null)
{
try
{
mycamera.autoFocus(new AutoFocusCallback()
{
public void onAutoFocus(boolean success, Camera camera)
{
}
});
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
};
}
timer2.schedule(timer, 500, 2500);
initCamera();
//mycamera.startPreview();
//mycamera.autoFocus(null);
} catch (IOException e) {
e.printStackTrace();
}
}
if(api==null)
{
api= new LPR();
String FilePath =Environment.getExternalStorageDirectory().toString()+"/lpr.key";
int nRet = api.Init(this,m_ROI[0], m_ROI[1], m_ROI[2], m_ROI[3], preHeight, preWidth,FilePath);
if(nRet!=0)
{
Toast.makeText(getApplicationContext(), "啟動失敗,請調整時間", Toast.LENGTH_SHORT).show();
Log.d("nRet ", nRet + "");
bInitKernal =false;
}
else
{
bInitKernal=true;
}
}
if(alertDialog==null){
alertDialog = new AlertDialog.Builder(this).create();
alertDialoginfo = new AlertDialog.Builder(this).create();
}
}
#Override
public void surfaceChanged(final SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
try {
if (mycamera != null) {
mycamera.setPreviewCallback(null);
mycamera.stopPreview();
mycamera.release();
mycamera = null;
}
} catch (Exception e) {
}
if(bInitKernal){
bInitKernal=false;
api = null;
}
if(toast!=null){
toast.cancel();
toast = null;
}
if(timer2!=null){
timer2.cancel();
timer2=null;
}
if(alertDialog!=null)
{
alertDialog.dismiss();
alertDialog.cancel();
alertDialog=null;
}
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
try {
if (mycamera != null) {
mycamera.setPreviewCallback(null);
mycamera.stopPreview();
mycamera.release();
mycamera = null;
}
} catch (Exception e) {
e.printStackTrace();
}
if(bInitKernal)
{
bInitKernal=false;
api = null;
}
finish();
if(toast!=null){
toast.cancel();
toast=null;
}
if(timer2!=null){
timer2.cancel();
timer2=null;
}
if(alertDialog!=null)
{
alertDialog.cancel();
alertDialog=null;
}
}
return super.onKeyDown(keyCode, event);
}
#TargetApi(14)
private void initCamera() {
Camera.Parameters parameters = mycamera.getParameters();
List<Camera.Size> list = parameters.getSupportedPreviewSizes();
preWidth = list.get(4).width;
preHeight = list.get(4).height;
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setPreviewSize(preWidth,preHeight);
if (!bROI) {
int l,t,r,b;
l = 100;
r = width-100;
int ntmpH =(r-l)*58/100;
t = (height-ntmpH)/2;
b = t+ntmpH;
double proportion = (double) width / (double) preHeight;
double hproportion=(double)height/(double) preWidth;
l = (int) (l /proportion);
t = (int) (t /hproportion);
r = (int) (r /proportion);
b = (int) (b / hproportion);
m_ROI[0]=l;
m_ROI[1]=t;
m_ROI[2]=r;
m_ROI[3]=b;
bROI = true;
}
if (parameters.getSupportedFocusModes().contains(
parameters.FOCUS_MODE_AUTO))
{
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);// 1连续对焦
}
mycamera.setPreviewCallback(LPR2Activity.this);
mycamera.setParameters(parameters);
mycamera.setDisplayOrientation(90); //一般機種
mycamera.startPreview();
}
public void onPreviewFrame(byte[] data, Camera camera) {
tackData = data;
Log.d("data length ", data.length + "");
ByteArrayInputStream bis = new ByteArrayInputStream(data);
resultStr = "";
if (!leaving&& bInitKernal ) {
Log.d("Status ", "開始判斷");
byte result[];//[] = new byte[10];
String res="";
result = api.VideoRec(tackData, preWidth, preHeight, 1);
Log.d("preWidth ", preWidth + "");
Log.d("preHeight", preHeight + "");
Log.d("width ", width + "");
Log.d("height", height + "");
try {
res = new String(result,"gb2312");
Log.d("try ", res);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
Log.d("Exception ", e.getMessage());
e.printStackTrace();
}
Log.d("res ", res);
if(res!=null&&!"".equals(res.trim()))
{
Camera.Parameters parameters = mycamera.getParameters();
resultStr =res.trim();
if (resultStr != "") {
leaving = true;
//拍照音效
MediaActionSound sound = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
}
Intent intent = new Intent();
intent.putExtra("strPltNo",resultStr);
setResult(2,intent);
finish();
}else{
Log.d("Status ", "未分配車牌號碼,請重拍");
}
}
}
}
#RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
public String pictureName() {
String str = "";
Time t = new Time();
t.setToNow(); // 取得系统时间。
int year = t.year;
int month = t.month + 1;
int date = t.monthDay;
int hour = t.hour; // 0-23
int minute = t.minute;
int second = t.second;
if (month < 10)
str = String.valueOf(year) + "0" + String.valueOf(month);
else {
str = String.valueOf(year) + String.valueOf(month);
}
if (date < 10)
str = str + "0" + String.valueOf(date + "_");
else {
str = str + String.valueOf(date + "_");
}
if (hour < 10)
str = str + "0" + String.valueOf(hour);
else {
str = str + String.valueOf(hour);
}
if (minute < 10)
str = str + "0" + String.valueOf(minute);
else {
str = str + String.valueOf(minute);
}
if (second < 10)
str = str + "0" + String.valueOf(second);
else {
str = str + String.valueOf(second);
}
return str;
}
public void Leave(View view) {
Intent intent = new Intent();
intent.putExtra("strPltNo","");
setResult(3,intent);
finish();
}
}
CameraX Log
Camera Log
With regards to the image analysis resolution, the documentation of ImageAnalysis.Builder.setTargetResolution() states that:
The maximum available resolution that could be selected for an
ImageAnalysis is limited to be under 1080p.
So setting a size of 2560x800 won't work as you expect. In return CameraX seems to be selecting the maximum ImageAnalysis resolution that has the same aspect ratio you requested (2560/800 = 1280/400).
I use this parser for downloading images to textview by Html.fromHtml():
public class URLImageParser implements Html.ImageGetter {
Context c;
TextView container;
Activity a;
int intrinsicHeight;
int intrinsicWidth;
boolean finishedExecuting;
public int getCounterImages() {
return counterImages;
}
public void setCounterImages(int counterImages) {
this.counterImages = counterImages;
}
public URLImageParser(TextView t, Context c, Activity a) {
this.c = c;
this.container = t;
this.a = a;
intrinsicHeight =0;
intrinsicWidth = 0;
finishedExecuting = false;
}
public Drawable getDrawable(String source) {
URLDrawable urlDrawable = new URLDrawable();
ImageGetterAsyncTask asyncTask =
new ImageGetterAsyncTask( urlDrawable);
asyncTask.execute(source);
return urlDrawable;
}
public class ImageGetterAsyncTask extends AsyncTask<String, Void, Drawable> {
URLDrawable urlDrawable;
boolean usesImageNotFoundDrawable = false;
public ImageGetterAsyncTask(URLDrawable d) {
this.urlDrawable = d;
}
#Override
protected Drawable doInBackground(String... params) {
String source = params[0];
return fetchDrawable(source);
}
#Override
protected void onPostExecute(Drawable result) {
if(result ==null){
usesImageNotFoundDrawable = true;
//the drawable wasn't found so use the image not found
//png
result = a.getResources().getDrawable(R.drawable.image_not_found);
} else {
usesImageNotFoundDrawable = false;
}
assert result != null;
intrinsicHeight = result.getIntrinsicHeight();
intrinsicWidth = result.getIntrinsicWidth();
DisplayMetrics dm = new DisplayMetrics();
((WindowManager) c.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels -50;
int height = width * intrinsicHeight / intrinsicWidth;
result.setBounds(0, 0, width, height);
urlDrawable.setBounds(0, 0, width, height);
urlDrawable.drawable = result;
URLImageParser.this.container.invalidate();
URLImageParser.this.container.setHeight((URLImageParser.this.container.getHeight() + height));
URLImageParser.this.container.refreshDrawableState();
// Pre ICS
URLImageParser.this.container.setEllipsize(null);
setFinishedExecuting(true);
}
public Drawable fetchDrawable(String urlString) {
try {
InputStream is = fetch(urlString);
return Drawable.createFromStream(is, "src");
} catch (Exception e) {
return null;
}
}
private InputStream fetch(String urlString) throws MalformedURLException, IOException {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();
}
}
public boolean getFinishedExecuting(){
return finishedExecuting;
}
public void setFinishedExecuting(boolean bool){
finishedExecuting = bool;
}
}
And everytime I get a good looking textview, but with additional white space in the end. I've tried to modify my formula, but it also didn't work in all textviews. How can I trim unnesecces rai height or whitespace from TextView in the end?
I want to crate curlview with dynemic data. I used imageview to display image into curlview because my api contain image in data. but image is not displayed into imageview how i do this?
Below is my code.
public class CurlActivity extends Activity {
private CurlView mCurlView;
public String cid;
public ArrayList<String>magazineidlist;
public String middata;
public String url;
public String imgurl;
public Bitmap bitmap;
public ImageLoader imageloder;
public ImageView imageView;
public ArrayList<String>imageurllist;
public GridImageAdapter gadapter;
public CurlActivity c;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_curl);
gadapter = new GridImageAdapter(c, imageurllist);
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
getAllMagazineById();
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
if(bundle!=null){
cid = bundle.getString("mid");
Log.d("magazine id", cid);
}
int index = 0;
if (getLastNonConfigurationInstance() != null) {
index = (Integer) getLastNonConfigurationInstance();
}
mCurlView = (CurlView) findViewById(R.id.curl);
}
#Override
public void onPause() {
super.onPause();
mCurlView.onPause();
}
#Override
public void onResume() {
super.onResume();
mCurlView.onResume();
}
#Override
public Object onRetainNonConfigurationInstance() {
return mCurlView.getCurrentIndex();
}
/**
* Bitmap provider.
*/
private class PageProvider implements CurlView.PageProvider {
// Bitmap resources.
private int[] mBitmapIds = { R.layout.sample};
//LinearLayout llout = (LinearLayout) findViewById(R.layout.sample);
#SuppressWarnings("unused")
//ImageView imageView = (ImageView) findViewById(R.id.imageviewsample);
#Override
public int getPageCount() {
return imageurllist.size();
}
private Bitmap loadBitmap(int width, int height, int index) {
LayoutInflater inflater =
(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Log.d("index",String.valueOf(index));
View v = inflater.inflate(mBitmapIds[index],null);
v.measure(
MeasureSpec.makeMeasureSpec(width,MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight()
,Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.draw(c);
return b;
}
#Override
public void updatePage(CurlPage page, int width, int height, int index) {
switch (index) {
// First case is image on front side, solid colored back.
default:
Bitmap front = loadBitmap(width, height, 0);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setColor(Color.rgb(180, 180, 180), CurlPage.SIDE_BACK);
break;
/*// Third case is images on both sides.
case 2: {
Bitmap front = loadBitmap(width, height, 1);
Bitmap back = loadBitmap(width, height, 3);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setTexture(back, CurlPage.SIDE_BACK);
break;
}
// Fourth case is images on both sides - plus they are blend against
// separate colors.
case 3: {
Bitmap front = loadBitmap(width, height, 2);
Bitmap back = loadBitmap(width, height, 1);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setTexture(back, CurlPage.SIDE_BACK);
page.setColor(Color.argb(127, 170, 130, 255),
CurlPage.SIDE_FRONT);
page.setColor(Color.rgb(255, 190, 150), CurlPage.SIDE_BACK);
break;
}
// Fifth case is same image is assigned to front and back. In this
// scenario only one texture is used and shared for both sides.
case 4:
Bitmap front = loadBitmap(width, height, 0);
page.setTexture(front, CurlPage.SIDE_BOTH);
page.setColor(Color.argb(127, 255, 255, 255),
CurlPage.SIDE_BACK);
break;*/
}
}
}
/**
* CurlView size changed observer.
*/
class SizeChangedObserver implements CurlView.SizeChangedObserver {
#Override
public void onSizeChanged(int w, int h) {
if (w > h) {
mCurlView.setViewMode(CurlView.SHOW_TWO_PAGES);
mCurlView.setMargins(.1f, .05f, .1f, .05f);
} else {
mCurlView.setViewMode(CurlView.SHOW_ONE_PAGE);
//mCurlView.setMargins(.1f, .1f, .1f, .1f);
}
}
}
public Bitmap GetBitmapfromUrl(String scr) {
try {
URL url=new URL(scr);
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input=connection.getInputStream();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeStream(input, null, options);
// Bitmap bmp = BitmapFactory.decodeStream(input);
return bitmap;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public void getAllMagazineById() {
new AsyncTask<Void, Void, String>() {
ProgressDialog mProgressDialog;
protected void onPostExecute(String result) {
mProgressDialog.dismiss();
magazineidlist = new ArrayList<String>();
imageurllist = new ArrayList<String>();
//imageloder = new ImageLoader(CurlActivity.this);
// LayoutInflater factory = LayoutInflater.from(CurlActivity.this);
// View child = factory.inflate(R.layout.sample, null);
// imageView = (ImageView)child.findViewById(R.id.imageviewsample);
//imageView = (ImageView)findViewById(R.id.imageviewsample);
try {
JSONObject jsob = new JSONObject(result.toString());
if (jsob.getString("msg").equalsIgnoreCase("Success")) {
JSONArray datajson = jsob.getJSONArray("data");
for (int i = 0; i < datajson.length(); i++) {
JSONObject c = datajson.getJSONObject(i);
middata = c.getString("magazine_id");
imgurl = c.getString("image_url");
magazineidlist.add(middata);
imageurllist.add(imgurl);
Log.d("imageurllist value at index" +i, imageurllist.get(i));
//imageloder.DisplayImage(imageurllist.get(i),imageView);
String url = imageurllist.get(i);
Log.d("url val", url);
}
mCurlView.setPageProvider(new PageProvider());
mCurlView.setSizeChangedObserver(new SizeChangedObserver());
//mCurlView.setCurrentIndex(0);
mCurlView.setBackgroundColor(0xFF202830);
} else if(jsob.getString("msg").equalsIgnoreCase("Failure")) {
System.out.println("not a valid data");
}
else
{
System.out.println("error");
}
} catch (Exception e) {
Log.e("error", "" + e);
}
}
private void startActivity(Intent i) {
// TODO Auto-generated method stub
}
#Override
protected String doInBackground(Void... arg0) {
// Creating service handler class instance
try {
HttpPost httppost1 = null;
HttpClient httpclient1 = new DefaultHttpClient();
httppost1 = new HttpPost(JsonKey.MAIN_URL);
// Add your data
List<NameValuePair> nameValuePairs1 = new ArrayList<NameValuePair>(
2);
nameValuePairs1.add(new BasicNameValuePair("action",
"GetMagazinePageImagesbyid"));
nameValuePairs1.add(new BasicNameValuePair("iMagezineId",
cid));
httppost1.setEntity(new UrlEncodedFormEntity(
nameValuePairs1));
// Execute HTTP Post Request
HttpResponse response1 = httpclient1.execute(httppost1);
BufferedReader in1 = new BufferedReader(
new InputStreamReader(response1.getEntity()
.getContent()));
StringBuffer sb1 = new StringBuffer("");
String line1 = "";
while ((line1 = in1.readLine()) != null) {
sb1.append(line1);
}
in1.close();
Log.e(" Get All magazine original data", sb1.toString());
return sb1.toString();
} catch (Exception e) {
Log.e("Get All magazine response problem", "" + e);
return " ";
}
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
mProgressDialog = new ProgressDialog(CurlActivity.this);
mProgressDialog.setTitle("");
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.setMessage("Please Wait...");
mProgressDialog.show();
}
}.execute();
}
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) {
// Log exception
return null;
}
}
Bitmap drawable_from_url(String url) throws java.net.MalformedURLException, java.io.IOException {
Bitmap x;
HttpURLConnection connection = (HttpURLConnection)new URL(url) .openConnection();
connection.setRequestProperty("User-agent","Mozilla/4.0");
connection.connect();
InputStream input = connection.getInputStream();
x = BitmapFactory.decodeStream(input);
return x;
}
public class GridImageAdapter extends BaseAdapter {
public Context mContext;
// public final String[] web;
// final int ImageId[];
public CurlActivity activity;
public ImageLoader imageloader;
// Constructor
public GridImageAdapter(CurlActivity c, ArrayList<String> imageUrl) {
// TODO Auto-generated constructor stub
mContext = c;
imageurllist = imageUrl;
imageloader = new ImageLoader(CurlActivity.this);
}
public int getCount() {
return imageurllist.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
View grid;
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
grid = new View(mContext);
grid = inflater.inflate(R.layout.sample, null);
ImageView img = (ImageView) grid.findViewById(R.id.imageviewsample);
imageloader.DisplayImage(imageurllist.get(position), img);
}
/*
* ImageView imageView; if (convertView == null) { imageView = new
* ImageView(mContext); imageView.setLayoutParams(new
* GridView.LayoutParams(85, 85));
* imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
* imageView.setPadding(8, 8, 8, 8); }
*/else {
grid = (View) convertView;
}
/*
* imageView.setImageResource(mThumbIds[position]); return
* imageView;
*/
return grid;
}
// Keep all Images in array
/*
* public Integer[] mThumbIds = { R.drawable.nightlife,
* R.drawable.coffee, R.drawable.shopping, R.drawable.seeanddo,
*
* };
*/
public Bitmap StringToBitMap(String encodedString) {
try {
byte[] encodeByte = Base64
.decode(encodedString, Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(encodeByte, 0,
encodeByte.length);
return bitmap;
} catch (Exception e) {
e.getMessage();
return null;
}
}
}
}
I need to generate 1D barcode image and set it to ImageView according to given 13-character code. Can anyone help me with this please?
You can use zxing library to generate barcode easily.
first, locate core.jar under libs folder.
libs/core.jar
You can download ZXing-2.1.zip from here.
http://repo1.maven.org/maven2/com/google/zxing/ (source)
After unzipping the file, find the jar file.
\ZXing-2.1\zxing-2.1\core\core.jar
And then write your own code like below.
import java.util.EnumMap;
import java.util.Map;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
public class BarcodeExampleActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout l = new LinearLayout(this);
l.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
l.setOrientation(LinearLayout.VERTICAL);
setContentView(l);
// barcode data
String barcode_data = "123456";
// barcode image
Bitmap bitmap = null;
ImageView iv = new ImageView(this);
try {
bitmap = encodeAsBitmap(barcode_data, BarcodeFormat.CODE_128, 600, 300);
iv.setImageBitmap(bitmap);
} catch (WriterException e) {
e.printStackTrace();
}
l.addView(iv);
//barcode text
TextView tv = new TextView(this);
tv.setGravity(Gravity.CENTER_HORIZONTAL);
tv.setText(barcode_data);
l.addView(tv);
}
/**************************************************************
* getting from com.google.zxing.client.android.encode.QRCodeEncoder
*
* See the sites below
* http://code.google.com/p/zxing/
* http://code.google.com/p/zxing/source/browse/trunk/android/src/com/google/zxing/client/android/encode/EncodeActivity.java
* http://code.google.com/p/zxing/source/browse/trunk/android/src/com/google/zxing/client/android/encode/QRCodeEncoder.java
*/
private static final int WHITE = 0xFFFFFFFF;
private static final int BLACK = 0xFF000000;
Bitmap encodeAsBitmap(String contents, BarcodeFormat format, int img_width, int img_height) throws WriterException {
String contentsToEncode = contents;
if (contentsToEncode == null) {
return null;
}
Map<EncodeHintType, Object> hints = null;
String encoding = guessAppropriateEncoding(contentsToEncode);
if (encoding != null) {
hints = new EnumMap<EncodeHintType, Object>(EncodeHintType.class);
hints.put(EncodeHintType.CHARACTER_SET, encoding);
}
MultiFormatWriter writer = new MultiFormatWriter();
BitMatrix result;
try {
result = writer.encode(contentsToEncode, format, img_width, img_height, hints);
} catch (IllegalArgumentException iae) {
// Unsupported format
return null;
}
int width = result.getWidth();
int height = result.getHeight();
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
}
}
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
private static String guessAppropriateEncoding(CharSequence contents) {
// Very crude at the moment
for (int i = 0; i < contents.length(); i++) {
if (contents.charAt(i) > 0xFF) {
return "UTF-8";
}
}
return null;
}
}
Thanks for your answers guys... In the meantime I found solution so here is what I used: http://www.onbarcode.com/products/android_barcode/barcodes/ean13.html
It's a library that worked fine for me so if anyone has the same issue I suggest using it.
Thanks again!
public Bitmap Ean13_Encode(String qrData, int qrCodeDimention) {
Bitmap bitmap= Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(qrData, null,
Contents.Type.TEXT, BarcodeFormat.EAN_13.toString(), qrCodeDimention);
try {
bitmap = qrCodeEncoder.encodeAsBitmap();
} catch (WriterException e) {
e.printStackTrace();
};
return bitmap;
};
public final class QRCodeEncoder {
private static final int WHITE = 0xFFFFFFFF;
private static final int BLACK = 0xFF000000;
private int dimension = Integer.MIN_VALUE;
private String contents = null;
private String displayContents = null;
private String title = null;
private BarcodeFormat format = null;
private boolean encoded = false;
public QRCodeEncoder(String data, Bundle bundle, String type, String format, int dimension) {
this.dimension = dimension;
encoded = encodeContents(data, bundle, type, format);
}
public String getContents() {
return contents;
}
public String getDisplayContents() {
return displayContents;
}
public String getTitle() {
return title;
}
private boolean encodeContents(String data, Bundle bundle, String type, String formatString) {
// Default to QR_CODE if no format given.
format = null;
if (formatString != null) {
try {
format = BarcodeFormat.valueOf(formatString);
} catch (IllegalArgumentException iae) {
// Ignore it then
}
}
if (format == null || format == BarcodeFormat.QR_CODE) {
this.format = BarcodeFormat.QR_CODE;
encodeQRCodeContents(data, bundle, type);
} else if (data != null && data.length() > 0) {
contents = data;
displayContents = data;
title = "Text";
}
return contents != null && contents.length() > 0;
}
private void encodeQRCodeContents(String data, Bundle bundle, String type) {
if (type.equals(Contents.Type.TEXT)) {
if (data != null && data.length() > 0) {
contents = data;
displayContents = data;
title = "Text";
}
} else if (type.equals(Contents.Type.EMAIL)) {
data = trim(data);
if (data != null) {
contents = "mailto:" + data;
displayContents = data;
title = "E-Mail";
}
} else if (type.equals(Contents.Type.PHONE)) {
data = trim(data);
if (data != null) {
contents = "tel:" + data;
displayContents = PhoneNumberUtils.formatNumber(data);
title = "Phone";
}
} else if (type.equals(Contents.Type.SMS)) {
data = trim(data);
if (data != null) {
contents = "sms:" + data;
displayContents = PhoneNumberUtils.formatNumber(data);
title = "SMS";
}
} else if (type.equals(Contents.Type.CONTACT)) {
if (bundle != null) {
StringBuilder newContents = new StringBuilder(100);
StringBuilder newDisplayContents = new StringBuilder(100);
newContents.append("MECARD:");
String name = trim(bundle.getString(ContactsContract.Intents.Insert.NAME));
if (name != null) {
newContents.append("N:").append(escapeMECARD(name)).append(';');
newDisplayContents.append(name);
}
String address = trim(bundle.getString(ContactsContract.Intents.Insert.POSTAL));
if (address != null) {
newContents.append("ADR:").append(escapeMECARD(address)).append(';');
newDisplayContents.append('\n').append(address);
}
Collection<String> uniquePhones = new HashSet<String>(Contents.PHONE_KEYS.length);
for (int x = 0; x < Contents.PHONE_KEYS.length; x++) {
String phone = trim(bundle.getString(Contents.PHONE_KEYS[x]));
if (phone != null) {
uniquePhones.add(phone);
}
}
for (String phone : uniquePhones) {
newContents.append("TEL:").append(escapeMECARD(phone)).append(';');
newDisplayContents.append('\n').append(PhoneNumberUtils.formatNumber(phone));
}
Collection<String> uniqueEmails = new HashSet<String>(Contents.EMAIL_KEYS.length);
for (int x = 0; x < Contents.EMAIL_KEYS.length; x++) {
String email = trim(bundle.getString(Contents.EMAIL_KEYS[x]));
if (email != null) {
uniqueEmails.add(email);
}
}
for (String email : uniqueEmails) {
newContents.append("EMAIL:").append(escapeMECARD(email)).append(';');
newDisplayContents.append('\n').append(email);
}
String url = trim(bundle.getString(Contents.URL_KEY));
if (url != null) {
// escapeMECARD(url) -> wrong escape e.g. http\://zxing.google.com
newContents.append("URL:").append(url).append(';');
newDisplayContents.append('\n').append(url);
}
String note = trim(bundle.getString(Contents.NOTE_KEY));
if (note != null) {
newContents.append("NOTE:").append(escapeMECARD(note)).append(';');
newDisplayContents.append('\n').append(note);
}
// Make sure we've encoded at least one field.
if (newDisplayContents.length() > 0) {
newContents.append(';');
contents = newContents.toString();
displayContents = newDisplayContents.toString();
title = "Contact";
} else {
contents = null;
displayContents = null;
}
}
} else if (type.equals(Contents.Type.LOCATION)) {
if (bundle != null) {
// These must use Bundle.getFloat(), not getDouble(), it's part of the API.
float latitude = bundle.getFloat("LAT", Float.MAX_VALUE);
float longitude = bundle.getFloat("LONG", Float.MAX_VALUE);
if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) {
contents = "geo:" + latitude + ',' + longitude;
displayContents = latitude + "," + longitude;
title = "Location";
}
}
}
}
public Bitmap encodeAsBitmap() throws WriterException {
if (!encoded) return null;
Map<EncodeHintType, Object> hints = null;
String encoding = guessAppropriateEncoding(contents);
if (encoding != null) {
hints = new EnumMap<EncodeHintType, Object>(EncodeHintType.class);
hints.put(EncodeHintType.CHARACTER_SET, encoding);
}
MultiFormatWriter writer = new MultiFormatWriter();
BitMatrix result = writer.encode(contents, format, dimension, dimension, hints);
int width = result.getWidth();
int height = result.getHeight();
int[] pixels = new int[width * height];
// All are 0, or black, by default
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
}
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
private String guessAppropriateEncoding(CharSequence contents) {
// Very crude at the moment
for (int i = 0; i < contents.length(); i++) {
if (contents.charAt(i) > 0xFF) { return "UTF-8"; }
}
return null;
}
private String trim(String s) {
if (s == null) { return null; }
String result = s.trim();
return result.length() == 0 ? null : result;
}
private String escapeMECARD(String input) {
if (input == null || (input.indexOf(':') < 0 && input.indexOf(';') < 0)) { return input; }
int length = input.length();
StringBuilder result = new StringBuilder(length);
for (int i = 0; i < length; i++) {
char c = input.charAt(i);
if (c == ':' || c == ';') {
result.append('\\');
}
result.append(c);
}
return result.toString();
}
}
Check out the answer on: Generate 1D barcode in Android
They suggest using IText which is a java PDF manipulation library. That also has the capability to generate barcode images.
You can find sample code in that question that I linked and also here
I want to set a TextView with SpannableString which is from the method below:
Html.fromHtml(String source, Html.ImageGetter imageGetter,
Html.TagHandler tagHandler)
But the ImageGetter here need to override the method below:
public abstract Drawable getDrawable(String source)
Because I need to get the drawable from the internet, I have to do it asynchronously and seems it is not.
How to make it work?
Thanks.
These guys did a great job, this is my solution using Square's Picasso library:
//...
final TextView textView = (TextView) findViewById(R.id.description);
Spanned spanned = Html.fromHtml(getIntent().getStringExtra(EXTRA_DESCRIPTION),
new Html.ImageGetter() {
#Override
public Drawable getDrawable(String source) {
LevelListDrawable d = new LevelListDrawable();
Drawable empty = getResources().getDrawable(R.drawable.abc_btn_check_material);;
d.addLevel(0, 0, empty);
d.setBounds(0, 0, empty.getIntrinsicWidth(), empty.getIntrinsicHeight());
new ImageGetterAsyncTask(DetailActivity.this, source, d).execute(textView);
return d;
}
}, null);
textView.setText(spanned);
//...
class ImageGetterAsyncTask extends AsyncTask<TextView, Void, Bitmap> {
private LevelListDrawable levelListDrawable;
private Context context;
private String source;
private TextView t;
public ImageGetterAsyncTask(Context context, String source, LevelListDrawable levelListDrawable) {
this.context = context;
this.source = source;
this.levelListDrawable = levelListDrawable;
}
#Override
protected Bitmap doInBackground(TextView... params) {
t = params[0];
try {
Log.d(LOG_CAT, "Downloading the image from: " + source);
return Picasso.with(context).load(source).get();
} catch (Exception e) {
return null;
}
}
#Override
protected void onPostExecute(final Bitmap bitmap) {
try {
Drawable d = new BitmapDrawable(context.getResources(), bitmap);
Point size = new Point();
((Activity) context).getWindowManager().getDefaultDisplay().getSize(size);
// Lets calculate the ratio according to the screen width in px
int multiplier = size.x / bitmap.getWidth();
Log.d(LOG_CAT, "multiplier: " + multiplier);
levelListDrawable.addLevel(1, 1, d);
// Set bounds width and height according to the bitmap resized size
levelListDrawable.setBounds(0, 0, bitmap.getWidth() * multiplier, bitmap.getHeight() * multiplier);
levelListDrawable.setLevel(1);
t.setText(t.getText()); // invalidate() doesn't work correctly...
} catch (Exception e) { /* Like a null bitmap, etc. */ }
}
}
My 2 cents... Peace!
Now I'm using an AsyncTask to download the images in the ImageGetter:
Spanned spannedContent = Html.fromHtml(htmlString, new ImageGetter() {
#Override
public Drawable getDrawable(String source) {
new ImageDownloadAsyncTask().execute(textView, htmlString, source);
return null;
}
}, null);
And set the text again into the TextView when the image has been downloaded.
Now it works. But It failed when I tried to do the TextView.postInvalidate() to redraw the downloaded images. I have to do setText() again in the AsyncTask.
Does anyone know why?
Here's my code that grabs all images in the html string (it's simplified from the original, so I hope it works):
private HashMap<String, Drawable> mImageCache = new HashMap<String, Drawable>();
private String mDescription = "...your html here...";
private void updateImages(final boolean downloadImages) {
if (mDescription == null) return;
Spanned spanned = Html.fromHtml(mDescription,
new Html.ImageGetter() {
#Override
public Drawable getDrawable(final String source) {
Drawable drawable = mImageCache.get(source);
if (drawable != null) {
return drawable;
} else if (downloadImages) {
new ImageDownloader(new ImageDownloader.ImageDownloadListener() {
#Override
public void onImageDownloadComplete(byte[] bitmapData) {
Drawable drawable = new BitmapDrawable(getResources(),
BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length));
try {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
} catch (Exception ex) {}
mImageCache.put(source, drawable);
updateImages(false);
}
#Override
public void onImageDownloadFailed(Exception ex) {}
}).execute(source);
}
return null;
}
}, null);
tvDescription.setText(spanned);
}
So basically what happens here is the ImageGetter will make a request for every image in the html description. If that image isn't in the mImageCache array and downloadImages is true, we run an async task to download that image. Once it has completed, we add the drawable into the hashmap, and then make a call to this method again (but with downloadImages as false so we don't risk an infinite loop), where the image will be able to be grabbed with the second attempt.
And with that, you'll need the ImageDownloader class that I used:
public class ImageDownloader extends AsyncTask {
public interface ImageDownloadListener {
public void onImageDownloadComplete(byte[] bitmapData);
public void onImageDownloadFailed(Exception ex);
}
private ImageDownloadListener mListener = null;
public ImageDownloader(ImageDownloadListener listener) {
mListener = listener;
}
protected Object doInBackground(Object... urls) {
String url = (String)urls[0];
ByteArrayOutputStream baos = null;
InputStream mIn = null;
try {
mIn = new java.net.URL(url).openStream();
int bytesRead;
byte[] buffer = new byte[64];
baos = new ByteArrayOutputStream();
while ((bytesRead = mIn.read(buffer)) > 0) {
if (isCancelled()) return null;
baos.write(buffer, 0, bytesRead);
}
return new AsyncTaskResult<byte[]>(baos.toByteArray());
} catch (Exception ex) {
return new AsyncTaskResult<byte[]>(ex);
}
finally {
Quick.close(mIn);
Quick.close(baos);
}
}
protected void onPostExecute(Object objResult) {
AsyncTaskResult<byte[]> result = (AsyncTaskResult<byte[]>)objResult;
if (isCancelled() || result == null) return;
if (result.getError() != null) {
mListener.onImageDownloadFailed(result.getError());
}
else if (mListener != null)
mListener.onImageDownloadComplete(result.getResult());
}
}