Canvas降低Android的图像质量

时间:2015-11-09 08:30:34

标签: android canvas bitmap bitmapfactory

我使用画布来修改我的图像。但是,我遇到了问题。如果我使用options.inSampleSize = 4;图像变得太小,质量下降。但是,如果我不给,它会从内存中溢出并出错。

    protected void onDraw(Canvas canvas) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 1;//Tried 4-But image quality too low


        Bitmap original1 = BitmapFactory.decodeFile(imagePathF, options);

      int width = original1.getWidth();
        int height = original1.getHeight();
        int bounding = dpToPx(Math.round(height));


        float xScale = ((float) bounding) / width2;
        float yScale = ((float) bounding) / height2;
        float scale = (xScale <= yScale) ? xScale : yScale;


        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale);


        Bitmap scaledBitmap = Bitmap.createBitmap(original1, 0, 0, width, height, matrix, true);

          Paint paint = new Paint();
        paint.setColor(Color.BLACK); // Text Color
        //Paint alphaChannel = new Paint();
        //alphaChannel.setAlpha(100);
        paint.setAlpha(100);
        paint.setTextSize(20 * scale);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); // Text Overlapping Pattern
        paint.setFlags(Paint.ANTI_ALIAS_FLAG);

        paint.getTextBounds(gText, 0, gText.length(), bounds);
        Typeface font = Typeface.createFromAsset(getAssets(), "Chantelli_Antiqua.ttf");
        paint.setTypeface(font);

        int x = (width2)/2;
        //int y = Math.round(height1)+(Math.round(height1) - Math.round(height2) / 2);
        int y = Math.round(height);
        int yOffset=calcYoff(gText, 0, 0, paint, canvas, Math.round(20 * scale), width);

// Bitmap scaledBitmap = Bitmap.createBitmap(original1,0,0,width,height,matrix,true);

              mDrawable = new BitmapDrawable(res, scaledBitmap);//original1);//
          canvas.drawColor(Color.TRANSPARENT);
            //canvas.drawBitmap(resizedBitmap, 0, 0, paint);
            mDrawable.draw(canvas);


            getDrawingCache().compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(new File(imagePathF)));



            super.onDraw(canvas);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("Error--------->", e.toString());
        }
    }

这是我当前的错误日志。

  

11-09 03:21:56.849 12345-12345 / com.example.chkee.appfront E / AndroidRuntime:FATAL EXCEPTION:main       处理:com.example.chkee.appfront,PID:12345       java.lang.IllegalArgumentException:位图大小超过32位               在android.graphics.Bitmap.nativeCreate(本机方法)               在android.graphics.Bitmap.createBitmap(Bitmap.java:812)               在android.graphics.Bitmap.createBitmap(Bitmap.java:789)               在android.graphics.Bitmap.createBitmap(Bitmap.java:720)               at com.example.chkee.ScrapBook.AddNotes $ Draw2d.onDraw(AddNotes.java:288)               在android.view.View.draw(View.java:15247)               在android.view.View.updateDisplayListIfDirty(View.java:14183)               在android.view.View.getDisplayList(View.java:14205)               在android.view.View.draw(View.java:14975)               在android.view.ViewGroup.drawChild(ViewGroup.java:3406)               在android.view.ViewGroup.dispatchDraw(ViewGroup.java:3199)               在android.view.View.updateDisplayListIfDirty(View.java:14178)               在android.view.View.getDisplayList(View.java:14205)               在android.view.View.draw(View.java:14975)               在android.view.ViewGroup.drawChild(ViewGroup.java:3406)               在android.view.ViewGroup.dispatchDraw(ViewGroup.java:3199)               在android.view.View.updateDisplayListIfDirty(View.java:14178)               在android.view.View.getDisplayList(View.java:14205)               在android.view.View.draw(View.java:14975)               在android.view.ViewGroup.drawChild(ViewGroup.java:3406)               在android.view.ViewGroup.dispatchDraw(ViewGroup.java:3199)               在android.view.View.updateDisplayListIfDirty(View.java:14178)               在android.view.View.getDisplayList(View.java:14205)               在android.view.View.draw(View.java:14975)               在android.view.ViewGroup.drawChild(ViewGroup.java:3406)               在android.view.ViewGroup.dispatchDraw(ViewGroup.java:3199)               在android.view.View.updateDisplayListIfDirty(View.java:14178)               在android.view.View.getDisplayList(View.java:14205)               在android.view.View.draw(View.java:14975)               在android.view.ViewGroup.drawChild(ViewGroup.java:3406)               在android.view.ViewGroup.dispatchDraw(ViewGroup.java:3199)               在android.view.View.draw(View.java:15250)               在android.widget.FrameLayout.draw(FrameLayout.java:598)               在com.android.internal.policy.impl.PhoneWindow $ DecorView.draw(PhoneWindow.java:2906)               在android.view.View.updateDisplayListIfDirty(View.java:14183)               在android.view.View.getDisplayList(View.java:14205)               在android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:273)               在android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:279)               在android.view.ThreadedRenderer.draw(ThreadedRenderer.java:318)               在android.view.ViewRootImpl.draw(ViewRootImpl.java:2536)               在android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2352)               在android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1982)               在android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)               在android.view.ViewRootImpl $ TraversalRunnable.run(ViewRootImpl.java:5891)               在android.view.Choreographer $ CallbackRecord.run(Choreographer.java:767)               在android.view.Choreographer.doCallbacks(Choreographer.java:580)               在android.view.Choreographer.doFrame(Choreographer.java:550)               在android.view.Choreographer $ FrameDisplayEventReceiver.run(Choreographer.java:753)               在android.os.Handler.handleCallback(Handler.java:739)               在android.os.Handler.dispatchMessage(Handler.java:95)               在android.os.Looper.loop(Looper.java:135)               在android.app.ActivityThread.main(ActivityThread.java:5292)               at java.lang.reflect.Method.invoke(Native Method)               在java.lang.reflect.Method.invoke(Method.java:372)               在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:904)               在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)

评论的部分显示了我尝试过的更多内容。 我也试过

Bitmap mBackgroundImage = Bitmap.createBitmap(Size, Size,
                Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBackgroundImage);

但它使我的整个图像变黑并且在它上面绘制不会影响画布,它仍然是黑色。

2 个答案:

答案 0 :(得分:0)

  1. 请勿创建包含完整heightwidth的位图。尝试在不影响纵横比的情况下减小高度或宽度。
  2. 如果inSampleSize = 4正在降低清晰度,请选择低于此值的内容。
  3. 为什么要创建另一个位图scaledBitmap?如果您真的想要创建缩放位图,请尝试Bitmap.createScaledBitmap()
  4. 如果您不需要Bitmap.recycle(),请不要忘记致电bitmap
  5. 有关上述各点的更多详细信息,请参阅此处:https://stackoverflow.com/a/33394336/4747587

    更新:崩溃的原因不是BitmapFactory.decodeFile(),而是因为以下代码行:

     Bitmap scaledBitmap = Bitmap.createBitmap(original1, 0, 0, width, height, matrix, true);
    

    将其替换为:

     Bitmap scaledBitmap= Bitmap.createScaledBitmap(original1, (int)(width/1.5f), (int)(height/1.5f), false); 
    

    所以,在这里使用1.5f值来适应你。您正尝试使用全分辨率创建与屏幕大小相同的bitmap。这将需要巨大的记忆力。相反,您需要创建一个较小的图像。所有这些都在上面的链接中有详细记载。

答案 1 :(得分:0)

如果您真的想要修改图像,可以在运行时进行修改。使用此链接可以找到更多详细信息。

Quality problems when resizing an image at runtime

但是,在调整大小或缩放位图后,还有另一种方法可以阻止“图像质量不佳”。您可以使用以下命令禁用来自资源的位图加载缩放:

Options options = new BitmapFactory.Options();
    options.inScaled = false;
    Bitmap source = BitmapFactory.decodeResource(a.getResources(), path, options);

同样 #Henry 建议您使用:

 Bitmap resizedBitmap = Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, false); 

How to get scaled bitmap with respect to screen size with out getting Out of memory exception