2009-09-10 6 views
7

Учитывая UIImage любого размера, я хочу сгенерировать квадратную «значку» размером в px пикселей в сторону, без каких-либо искажений (растяжения). Тем не менее, я сталкиваюсь с небольшой хваткой. Не совсем уверен, где проблема. Вот что я делаю до сих пор.Правильное использование UIRectClip для масштабирования UIImage до размера значка

Во-первых, учитывая UImagesize, я определить три вещи: 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); 
} 

Теперь, скажем, у вас есть изображение 640px в ширину и 480px, и мы хотим получить значок 50px x 50px. Ширина больше высоты, так что наши расчеты:

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

Далее я создаю CGRectrect, что является достаточно большим, чтобы быть обрезаны до нашего желаемого размера значка без искажений, плюс 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,5px шириной 50px с высоким прямоугольником для работы с ним и отсекающий прямоугольник, который захватывает «среднюю» часть 50x50.

На домашнем участке! Затем создадим наш контекст изображения, нарисуем UIImage (здесь myImage здесь) в прямоугольник, зададим обрезающий прямоугольник, получим (предположительно теперь обрезанное) изображение, воспользуемся им и, наконец, очистим наш контекст изображения:

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

// Do something with the icon here ... 

UIGraphicsEndImageContext(); 

Только одна проблема: отсечения никогда не происходит! Я получаю изображение размером 63px в ширину x 50px. :(

Возможно, я неправильно использую/не понимаю UIRectClip? Я пытался перетасовать различные вещи: обмен rect и clipRect, перемещение UIRectClip до drawInRect:. Нет кубиков.

Я попытался найти пример этого метода онлайн, но безрезультатно. Для записи, UIRectClip определяется как:

Изменяет текущий путь отсечения по , пересекающая его с указанным прямоугольника.

шаркая вещи вокруг заставляет нас немного ближе:

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

Теперь у нас нет искажений, но обрезается изображение не по центру оригинала, как я ожидал.Тем не менее, по крайней мере, изображение равно 50x50, хотя имена переменных теперь загрязнены в результате упомянутого перетасовки. (Я с уважением оставлю переименование в качестве упражнения для читателя.)

ответ

7

Eureka! Я немного перепутал. Это работает:

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 x 50 (в этом примере).

Возможно, есть более простой способ. Если да, пожалуйста, взвесьте!

1

Я хотел достичь подобной вещи, но наш ответ от оригинального плаката не совсем сработал. Он исказил изображение. Это может быть только потому, что он не отправлял все решения и изменили некоторые как переменные инициализируются:

(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; 
} 
+0

Спасибо за разделение этого! Прошло некоторое время с тех пор, как я посмотрел, что у меня получилось. Я определенно не хотел или не искал никаких искажений, используя мой метод. Ваш «самый большой возможный квадрат» звучит разумно, и я очень рад слышать, что UIRectClip не нужен. (Другие читатели, пожалуйста, взвесьте и посмотрите, как это вам тоже!) –

+0

Благодарим вас, в частности, за предложение «Также не обязательно использовать UIClipRect - если вы сделаете контекст размером с изображением, которое хотите извлечь, никакой фактический рисунок не будет сделан вне этого rect так или иначе " – xaphod

0

wheeliebin ответов является правильным, но он забыл минус знак перед Desty

destRect = CGRectMake(0, -destY, destSize, destHeight);