एंड्रॉइड में बिटमैप से परिपत्र क्षेत्र की फसल कैसे करें


108

मेरे पास एक बिटमैप है और मैं इस बिटमैप से एक परिपत्र क्षेत्र में फसल लेना चाहता हूं। सर्कल के बाहर के सभी पिक्सेल पारदर्शी होने चाहिए। मैं यह कैसे कर सकता हूँ?

यहां छवि विवरण दर्ज करें

जवाबों:


216

लंबे समय तक मंथन के बाद मैंने इसका हल ढूंढ लिया है

public Bitmap getCroppedBitmap(Bitmap bitmap) {
    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
            bitmap.getHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    final int color = 0xff424242;
    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    // canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
    canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
            bitmap.getWidth() / 2, paint);
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(bitmap, rect, rect, paint);
    //Bitmap _bmp = Bitmap.createScaledBitmap(output, 60, 60, false);
    //return _bmp;
    return output;
}

1
आप इसे गोलाकार क्लिपिंग पथ के खिलाफ बिटमैप को क्लिप करके भी कर सकते हैं। आप हर बार बिटमैप को आकर्षित करने के लिए ऐसा कर सकते हैं, जिसका अर्थ है कि आप वास्तव में पारदर्शी पिक्सल के साथ बिटमैप नहीं बना पाएंगे, या आप क्लिप्ड बिटमैप को एक बफर में खींच सकते हैं जिसे पारदर्शी से पहले ही मिटा दिया गया है। मुझे लगता है कि या तो इससे थोड़ा तेज और सरल होगा।
जीन

1
धन्यवाद। आपका कोड शानदार काम करता है। अब मैं पथ (बहुभुज) का उपयोग करके भी फसल ले सकता हूं।
प्रियध्वज

2
यह विधि staticसमान स्थिर विधियों की गैर-तात्कालिक उपयोगिता वर्ग में बनाई और उपयोग की जा सकती है ।
मैट लोगन

1
क्या आपको यहां त्रिज्या के रूप में 2 से विभाजित ऊंचाई और चौड़ाई का न्यूनतम उपयोग नहीं करना चाहिए? canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth() / 2, paint);
वरवारा कलिनािना

3
3 मुख्य बिंदु हैं: 1) एक खाली बिटमैप बनाएं और एक सर्कल बनाएं। 2) SRC_IN के लिए xfermode सेट करें। 3) उस कैनवास सीमा पर असली बिटमैप ड्रा करें। तो, पेंट का रंग और अन्य कैनवास ड्राइंग का कोई फायदा नहीं है।
लाइम ज़ोय

44

आयतों से वृत्त बनाने के लिए

public static Bitmap getCircularBitmap(Bitmap bitmap) {
    Bitmap output;

    if (bitmap.getWidth() > bitmap.getHeight()) {
        output = Bitmap.createBitmap(bitmap.getHeight(), bitmap.getHeight(), Config.ARGB_8888);
    } else {
        output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getWidth(), Config.ARGB_8888);
    }

    Canvas canvas = new Canvas(output);

    final int color = 0xff424242;
    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

    float r = 0;

    if (bitmap.getWidth() > bitmap.getHeight()) {
        r = bitmap.getHeight() / 2;
    } else {
        r = bitmap.getWidth() / 2;
    }

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawCircle(r, r, r, paint);
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(bitmap, rect, rect, paint);
    return output;
}

1
मैं सुझाव दूंगा कि पारदर्शी सर्कल में कट आउट के साथ शीर्ष इमेजव्यू के साथ एक फ्रैमेलेयआउट में दो छवि का उपयोग कर।
डीजल

36

आप का उपयोग परिपत्र अपने imageView बना सकते हैं RoundedBitmapDrawable

यहाँ राउंड प्राप्त करने के लिए कोड है Imageview:

ImageView profilePic=(ImageView)findViewById(R.id.user_image);

//get bitmap of the image
Bitmap imageBitmap=BitmapFactory.decodeResource(getResources(),  R.drawable.large_icon);
RoundedBitmapDrawable roundedBitmapDrawable=RoundedBitmapDrawableFactory.create(getResources(), imageBitmap);

//setting radius
roundedBitmapDrawable.setCornerRadius(50.0f);
roundedBitmapDrawable.setAntiAlias(true);
profilePic.setImageDrawable(roundedBitmapDrawable);

इस v4 समर्थन पुस्तकालय विकल्प को दिखाने के लिए धन्यवाद। मुझे नहीं लगता कि मुझे इसके बारे में पता चला होगा अन्यथा।
CFJ90210

8
और setCircerRadius (50.0f) के बजाय सेट सर्कुलर (सच) का उपयोग करके ड्रॉएबल को एक सर्कल बना देता है। नोट: छवि चौकोर होना चाहिए या पहलू अनुपात दोष है ...
मार्को शमित्ज़

31

@ गेन ने ऊपर दिए गए जवाब पर एक टिप्पणी की जो clipPathएक छवि को एक सर्कल के रूप में क्रॉप करने के विकल्प के रूप में उपयोग करने का सुझाव दिया ।

निम्नलिखित इस का एक साफ कार्यान्वयन है:

    public static Bitmap GetBitmapClippedCircle(Bitmap bitmap) {

        final int width = bitmap.getWidth();
        final int height = bitmap.getHeight();
        final Bitmap outputBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);

        final Path path = new Path();
        path.addCircle(
                  (float)(width / 2)
                , (float)(height / 2)
                , (float) Math.min(width, (height / 2))
                , Path.Direction.CCW);

        final Canvas canvas = new Canvas(outputBitmap);
        canvas.clipPath(path);
        canvas.drawBitmap(bitmap, 0, 0, null);
        return outputBitmap;
    }

इसे एक उपयोगिता वर्ग में जोड़ा जा सकता है।


4
मैं बहुत समान कोड पोस्ट करने वाला था। डेवलपर के अनुसार यह समस्या है ।android.com/guide/topics/graphics/hardware-accel.html, क्लिपपैथ हार्डवेयर त्वरण के साथ समर्थित नहीं है। मैं वास्तव में एक ऐप में उस समस्या में भाग गया और सोच रहा था कि क्या चल रहा है। नया हार्डवेयर इसे ठीक करने लगता है, हालाँकि (Google टैबलेट की तरह)। आपके कोड में एक और संभावित सफाई: बिटमैप को ड्रॉ करते समय आपको रेक्ट-टू-रेक्ट रूपांतरण की आवश्यकता नहीं है। आप बस कह सकते हैं c.drawBitmap(b, 0, 0, null);, जो डिफ़ॉल्ट पहचान परिवर्तन का उपयोग करता है।
जीन

हार्डवेयर त्वरण का उपयोग करते समय आप क्लिपपैथ का उपयोग कैसे कर सकते हैं?
स्पीडनोमैड्स

मैं मूल रूप से पहले इस समाधान का उपयोग कर रहा था, लेकिन आउटपुट में किनारों को झटका लगा था। @Altaf से समाधान बेहतर काम करता है
dironeill

स्टेटस बार में नोटिफिकेशन में इस्तेमाल की गई क्रॉपिंग इमेज के लिए बढ़िया काम करता है
डेमियन पेटला

14

मुझे लगता है कि यह समाधान किसी भी प्रकार के आयत के साथ बेहतर काम करता है, यदि आप छवि को छोटा या बड़ा करना चाहते हैं, तो पिक्सेल आकार बदल दें:

public static Bitmap getCircleBitmap(Bitmap bm) {

        int sice = Math.min((bm.getWidth()), (bm.getHeight()));

        Bitmap bitmap = ThumbnailUtils.extractThumbnail(bm, sice, sice);

        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(output);

        final int color = 0xffff0000;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);

        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setFilterBitmap(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawOval(rectF, paint);

        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth((float) 4);
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        return output;
    }

11

यह वास्तविक बिटमैप को क्रॉप किए बिना xml में भी की गई लापरवाही हो सकती है, आपको बस एक परिपत्र छवि मास्क बनाने और अपनी वास्तविक छवि पर जगह बनाने की आवश्यकता है। यहाँ कोड का टुकड़ा है जो मैंने उपयोग किया है:

circle.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
    <gradient android:startColor="#00FFFFFF" android:endColor="#00FFFFFF"
        android:angle="270"/>
     <stroke android:width="10dp" android:color="#FFAAAAAA"/>

your_layout.xml (अनदेखा करें "Android: scaleType =" fitXY "" यदि आपको इसकी आवश्यकता नहीं है)

<RelativeLayout

        android:id="@+id/icon_layout"
        android:layout_width="@dimen/icon_mask"
        android:layout_height="@dimen/icon_mask"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true" >

        <ImageView
            android:id="@+id/icon"
            android:layout_width="@dimen/icon"
            android:layout_height="@dimen/icon"
            android:layout_centerInParent="true"
            android:scaleType="fitXY" >
        </ImageView>

        <ImageView
            android:id="@+id/icon_mask"
            android:layout_width="@dimen/icon_mask"
            android:layout_height="@dimen/icon_mask"
            android:layout_centerInParent="true"
            android:background="@drawable/circle"
            android:scaleType="fitXY" >
        </ImageView>
    </RelativeLayout>

dimen.xml


<dimen name="icon">36dp</dimen>
<dimen name="icon_mask">55dp</dimen>

यहां छवि विवरण दर्ज करें

आउटपुट चित्र देखें:

आशा है, यह किसी के लिए उपयोगी हो सकता है !!! :)


ऐसा लगता है कि यह केवल तभी काम कर रहा है जब छवि में पारदर्शी पृष्ठभूमि हो जो सर्कल से छोटी हो ...
meDamian

4
तुम सिर्फ दूसरे के ऊपर एक imageView शब्दों में कहें, यह एक मुखौटा नहीं है :)
Climbatize

@Ash सुनिश्चित करें, आप सही :) मैं सिर्फ यह है कि इस तरह से आप नहीं वास्तव में 'फसल' मूल छवि, मूल पोस्टर से पूछा के रूप में;)
Climbatize

8

आप इस कोड का उपयोग कर सकते हैं, यह काम करेगा

 private Bitmap getCircleBitmap(Bitmap bitmap) {
        final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        final Canvas canvas = new Canvas(output);

        final int color = Color.RED;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawOval(rectF, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        bitmap.recycle();

        return output;
    }

यह एंड्रॉइड एपीआई <28 पर अच्छी तरह से काम करता है, लेकिन java.lang.IllegalArgumentException के साथ क्रैश होता है: सॉफ़्टवेयर रेंडरिंग एंड्रॉइड 28 पर हार्डवेयर बिटमैप्स का समर्थन नहीं करता है
लुकियन इकोब

7

आप इस कोड का उपयोग कर सकते हैं, यह काम करेगा

public Bitmap getRoundedShape(Bitmap scaleBitmapImage) {
    int targetWidth = 110;
    int targetHeight = 110;
    Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, 
            targetHeight,Bitmap.Config.ARGB_8888);

    Canvas canvas = new Canvas(targetBitmap);
    Path path = new Path();
    path.addCircle(((float) targetWidth - 1) / 2,
            ((float) targetHeight - 1) / 2,
            (Math.min(((float) targetWidth), 
                    ((float) targetHeight)) / 2),
                    Path.Direction.CCW);

    canvas.clipPath(path);
    Bitmap sourceBitmap = scaleBitmapImage;
    canvas.drawBitmap(sourceBitmap, 
            new Rect(0, 0, sourceBitmap.getWidth(),
                    sourceBitmap.getHeight()), 
                    new Rect(0, 0, targetWidth, targetHeight), new Paint(Paint.FILTER_BITMAP_FLAG));
    return targetBitmap;
}

3

bitmap.recycle()यदि आपको इसकी आवश्यकता नहीं है, तो मैं इसे जोड़ने की सलाह देता हूं, यह आउटऑफमेरी त्रुटि को रोक देगा।


3

यहाँ विस्तार विधि का उपयोग करते हुए कोटलीन संस्करण है

/**
 * Creates new circular bitmap based on original one.
 */
fun Bitmap.getCircularBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap {
    // circle configuration
    val circlePaint = Paint().apply { isAntiAlias = true }
    val circleRadius = Math.max(width, height) / 2f

    // output bitmap
    val outputBitmapPaint = Paint(circlePaint).apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) }
    val outputBounds = Rect(0, 0, width, height)
    val output = Bitmap.createBitmap(width, height, config)

    return Canvas(output).run {
        drawCircle(circleRadius, circleRadius, circleRadius, circlePaint)
        drawBitmap(this@getCircularBitmap, outputBounds, outputBounds, outputBitmapPaint)
        output
    }
}

2

मटर के लिए जो आयत (मुझे) का केंद्र चाहते हैं, काटने से पहले इसे जोड़ें:

    public static Bitmap cropBitmapToBlock(Bitmap bitmap) {
    if (bitmap.getWidth() >= bitmap.getHeight()){
        return Bitmap.createBitmap(
                bitmap,
                bitmap.getWidth()/2 - bitmap.getHeight()/2,
                0,
                bitmap.getHeight(),
                bitmap.getHeight()
        );
    }else{
        return Bitmap.createBitmap(
                bitmap,
                0,
                bitmap.getHeight()/2 - bitmap.getWidth()/2,
                bitmap.getWidth(),
                bitmap.getWidth()
        );
    }
} 

बिटमैप के Android फसल केंद्र


2

[Jachumbelechao Unto Mantekilla] उत्तर के आधार पर, यह कोड एक कोटलिन की तलाश में लोगों के लिए एक आकर्षण की तरह काम करता है:

fun cropCircleFromBitmap(originalBitmap: Bitmap): Bitmap {
    val size = Math.min(originalBitmap.width, originalBitmap.height)
    val bitmap = ThumbnailUtils.extractThumbnail(originalBitmap, size, size)
    var output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(output)
    val paint = Paint()
    val rect = Rect(0, 0, bitmap.width, bitmap.height)
    val rectF = RectF(rect)
    paint.isAntiAlias = true
    paint.isDither = true
    paint.isFilterBitmap = true
    canvas.drawARGB(0, 0, 0, 0)
    paint.color = 0xffff0000.toInt()
    canvas.drawOval(rectF, paint)
    paint.color = Color.BLUE
    paint.style = Paint.Style.STROKE
    paint.strokeWidth = 4f
    paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
    canvas.drawBitmap(bitmap, rect, rect, paint)
    return output
}

आप इसे एक विस्तार समारोह में बदल सकते हैं
greenspand

मज़ा की तरह कुछ Bitmap.getCircleCroppedBitmap (): Bitmap {} और मूलबाइटमैप के बजाय इसका उपयोग करें
greenspand

तब आप इसे इस तरह इस्तेमाल कर सकते हैं: img_user_photo.setImageBitmap (photo.getCircleCroppedBitmap ())
greenspand

जहां फोटो बिटमैप ऑब्जेक्ट है जिसे फंक्शन के साथ बढ़ाया गया है
greenspand

1

अब, सही उत्तर:

private Bitmap getCroppedBitmap(Bitmap bitmap, Integer cx, Integer cy, Integer radius) {
    int diam = radius << 1;
    Bitmap targetBitmap = Bitmap.createBitmap(diam, diam, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(targetBitmap);
    final int color = 0xff424242;
    final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawCircle(radius, radius, radius, paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    canvas.drawBitmap(bitmap, -cx+radius, -cy+radius, paint);
    return targetBitmap;
}

1
Cx और cy क्या हैं?
कार्तिक चुघ

1
@ K_7, यह एक सर्कल का केंद्र है
मास्टर

1

कोटिन फ़्यूकेनियन

 fun getRoundedCornerBitmap(bitmap: Bitmap, pixels: Int): Bitmap {
            val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
            val canvas = Canvas(output)

            val color = -0xbdbdbe
            val paint = Paint()
            val rect = Rect(0, 0, bitmap.width, bitmap.height)
            val rectF = RectF(rect)
            val roundPx = pixels.toFloat()

            paint.isAntiAlias = true
            canvas.drawARGB(0, 0, 0, 0)
            paint.color = color
            canvas.drawRoundRect(rectF, roundPx, roundPx, paint)

            paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
            canvas.drawBitmap(bitmap, rect, rect, paint)

            return output
        }

इसे इस कोड से कॉल करें

 holder.itemFriendImage.setImageBitmap(ImageConverter.getRoundedCornerBitmap(bitmap,600))

1

मेरा मानना ​​है कि सबसे आसान उपाय यह है कि आप अपने बिटमैप का एक बिटमैप तैयार करें, इसे अपने पेंट ऑब्जेक्ट में पास करें और फिर कैनवास की तरह कुछ कॉल करें। Circle (cx, cy, radius, paint);

उदाहरण के लिए

Paint p = new Paint();
p.setShader(new BitmapShader(myBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
canvas.drawCircle(getWidth() / 2, getHeight() / 2, getHeight() / 2, p);

ऐसा https://github.com/hdodenhof/CircleImageView ने भी किया है, आप स्रोत कोड यहां पढ़ सकते हैं: https://github.com/hdodenhof/CircleImageView/blob/master/circleimageview/src/main/java /de/hdodenhof/circleimageview/CircleImageView.java


0
**Jst Add this to your image Id and get the circuler image.**

 imgUserProfile.setImageBitmap(getCircularCenterCropBitmap(bitmap, (int) (150 * denisty)));

Method:-

public void Bitmap getCircularCenterCropBitmap(Bitmap originalBmp, int diameter) {
        Bitmap resizedBmp = BitmapUtils.getScaledCroppedBitmap(originalBmp, diameter, diameter);
        return BitmapUtils.getRoundedCircularBitmap(resizedBmp, diameter / 2);
    }

-1

यकीन नहीं होता कि यह एक प्रोग्रामिंग सवाल है लेकिन ...

सबसे आसान उपाय यह होगा कि स्रोत बिटमैप में बाहरी क्षेत्र को पारदर्शी बनाया जाए। अन्यथा, आपको गणना करनी होगी कि कौन से पिक्सेल सर्कल के बाहर हैं, और अल्फा को तदनुसार सेट करें (पूर्ण पारदर्शिता के लिए अल्फा = 0)।


ईमानदार होने के लिए, मैं आपका रास्ता बना रहा हूं, यह काम लगता है लेकिन हम सीमा की समस्या को हल नहीं कर सकते, क्या आप नहीं?
विंससट्लिंग

बॉर्डर "jaggyness" को dithering और / या antialiasing द्वारा संबोधित किया जाता है। स्वीकार्य होने के लिए कुछ एल्गोरिदम के लिए आप ऑनलाइन देख सकते हैं। लेकिन ध्यान रखें कि आयताकार पिक्सेल और घटता में हमेशा ये मुद्दे होंगे।
मंडिस्सा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.