الاستخدام السليم لـ UIRectClip لتغيير حجم UIImage إلى حجم الرمز

StackOverflow https://stackoverflow.com/questions/1405994

  •  05-07-2019
  •  | 
  •  

سؤال

نظرا ل UIImage من أي بُعد، أرغب في إنشاء نسخة بحجم "أيقونة" مربعة، px بكسل إلى الجانب، دون أي تشويه (تمتد).ومع ذلك، فأنا أواجه عقبة صغيرة.لست متأكدا تماما أين تكمن المشكلة.وإليكم ما أفعله حتى الآن.

أولا، نظرا ل UImage size, ، أحدد ثلاثة أشياء:ال ratio لاستخدامها عند تصغير الصورة؛أ delta (الفرق بين حجم الرمز المطلوب والجانب الأطول)، و offset (والذي يُستخدم لمعرفة الإحداثيات الأصلية عند قص الصورة):

 if (size.width > size.height) {
   ratio = px / size.width;
   delta = (ratio*size.width - ratio*size.height);
   offset = CGPointMake(delta/2, 0);
 } else {
   ratio = px / size.height;
   delta = (ratio*size.height - ratio*size.width);
   offset = CGPointMake(0, delta/2);
 }

الآن، لنفترض أن لديك صورة بعرض 640 بكسل وارتفاع 480 بكسل، ونريد الحصول على رمز بحجم 50 بكسل × 50 بكسل من هذا.العرض أكبر من الارتفاع، لذلك حساباتنا هي:

ratio = 50px / 640px = 0.078125
delta = (ratio * 640px) - (ratio * 480px) = 50px - 37.5px = 12.5px
offset = {x=6.25, y=0}

بعد ذلك، أقوم بإنشاء CGRect rect وهو كبير بما يكفي ليتم اقتصاصه إلى حجم الرمز المطلوب دون تشويه، بالإضافة إلى أ clipRect لأغراض القطع:

CGRect rect = CGRectMake(0.0, 0.0, (ratio * size.width) + delta,
                                   (ratio * size.height) + delta);
CGRect clipRect = CGRectMake(offset.x, offset.y, px, px);

باستبدال القيم التي لدينا في الأعلى نحصل على:

rect = origin {x=0.0, y=0.0}, size {width=62.5, height=50.0}
clipRect = origin {x=6.25, y=0}, size {width=50.0, height=50.0}

إذن لدينا الآن مستطيل بعرض 62.5 بكسل وارتفاع 50 بكسل للعمل به، ومستطيل القطع الذي يلتقط الجزء "الأوسط" مقاس 50 × 50.

إلى امتداد المنزل!بعد ذلك، قمنا بإعداد سياق الصورة الخاص بنا، ورسم UIImage (مُسَمًّى myImage هنا) في المستطيل، قم بتعيين مستطيل القطع، واحصل على الصورة (المفترض أنها مقصوصة الآن)، واستخدمها، وأخيرًا قم بتنظيف سياق الصورة لدينا:

 UIGraphicsBeginImageContext(rect.size);
 [myImage drawInRect:rect]; 
 UIRectClip(clipRect);
 UIImage *icon = UIGraphicsGetImageFromCurrentImageContext();

 // Do something with the icon here ...

 UIGraphicsEndImageContext();

مشكلة واحدة فقط:القطع لا يحدث أبدا!انتهى بي الأمر بصورة بعرض 63 بكسل وارتفاع 50 بكسل. :(

ربما أسيء الاستخدام/سوء الفهم UIRectClip؟لقد حاولت خلط أشياء مختلفة:مبادلة استخدام rect و clipRect, ، متحرك UIRectClip قبل رسمإنريكت:.لا النرد.

وحاولت البحث عن مثال لهذه الطريقة عبر الإنترنت أيضًا، ولكن دون جدوى.للعلم، UIRectClip يعرف ب:

يعدل مسار القطع الحالي عن طريق التقاطع مع المستطيل المحدد.

خلط الأشياء يجعلنا أقرب قليلاً:

UIGraphicsBeginImageContext(clipRect.size);
UIRectClip(rect);
[myImage drawInRect:rect];

الآن ليس لدينا تشويه، ولكن الصورة المقطوعة ليست مركزة على الصورة الأصلية كما توقعت.ومع ذلك، فإن حجم الصورة على الأقل هو 50 × 50، على الرغم من أن أسماء المتغيرات قد تم خطأها الآن نتيجة الخلط المذكور.(سأترك إعادة التسمية بكل احترام كتمرين للقارئ.)

هل كانت مفيدة؟

المحلول

يوريكا!لقد كانت الأمور مختلطة بعض الشيء.هذا يعمل:

CGRect clipRect = CGRectMake(-offset.x, -offset.y,
                             (ratio * size.width) + delta,
                             (ratio * size.height) + delta);
UIGraphicsBeginImageContext(CGSizeMake(px, px));
UIRectClip(clipRect);
[myImage drawInRect:clipRect];
UIImage *icon = UIGraphicsGetImageFromCurrentImageContext();

// Do something with the icon here ...

UIGraphicsEndImageContext();

لا مزيد من الحاجة ل rect.يبدو أن الحيلة تستخدم ملف سلبي إزاحة في مستطيل القطع، وبالتالي محاذاة أصل المكان الذي نريد التقاط صورتنا مقاس 50 × 50 (في هذا المثال).

ربما هناك طريقة أسهل.إذا كان الأمر كذلك، يرجى وزنها!

نصائح أخرى

كنت أرغب في تحقيق شيء مماثل ولكني وجدت أن الإجابة الواردة من الملصق الأصلي لم تنجح تمامًا.لقد شوهت الصورة.قد يكون هذا فقط لأنه لم ينشر الحل بالكامل وقام بتغيير بعض كيفية تهيئة المتغيرات:

 (if (size.width > size.height) 
       ratio = px / size.width;

كان الحل خاطئًا (الذي أراد استخدام أكبر مربع ممكن من الصورة المصدر).كما أنه ليس من الضروري استخدام UIClipRect - إذا قمت بجعل السياق بحجم الصورة التي تريد استخراجها، فلن يتم إجراء أي رسم فعلي خارج هذا المستقيم على أي حال.إنها مجرد مسألة تغيير حجم الصورة وتعويض أحد إحداثيات الأصل.لقد نشرت الحل الخاص بي أدناه:

+(UIImage *)makeIconImage:(UIImage *)image
{
    CGFloat destSize = 400.0;
    CGRect rect = CGRectMake(0, 0, destSize, destSize);

    UIGraphicsBeginImageContext(rect.size);

    if(image.size.width != image.size.height)
    {
        CGFloat ratio;
        CGRect destRect;

        if (image.size.width > image.size.height)
        {
            ratio = destSize / image.size.height;

            CGFloat destWidth = image.size.width * ratio;
            CGFloat destX = (destWidth - destSize) / 2.0;

            destRect = CGRectMake(-destX, 0, destWidth, destSize);

        }
        else
        {
            ratio = destSize / image.size.width;

            CGFloat destHeight = image.size.height * ratio;
            CGFloat destY = (destHeight - destSize) / 2.0;

            destRect = CGRectMake(0, destY, destSize, destHeight);
        }
        [image drawInRect:destRect];
    }
    else
    {
        [image drawInRect:rect];
    }
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return scaledImage;
}

إجابات wheeliebin صحيحة لكنه نسي علامة الطرح أمام القدر

destRect = CGRectMake(0, -destY, destSize, destHeight);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top