Перейти к содержанию
Fire Monkey от А до Я
  • 0

Как программно реализовать подгонку картинки в TImage в RunTime, так же как это делает MultiResBitmap Editor?


Andrey Efimov

Вопрос

  • Модераторы
Баг замечен на Android.
 
Предположим у нас есть приложение, в котором по нажатию на кнопку подгружается картинка в «TImage» (Width: 310; Height: 150). Картинки могут быть как меньшего размера (например, Width: 215; Height: 150), так и большего (Width: 440; Height: 150). Высота указана одинаковой для примера, чтобы было проще понять, как выглядит баг.
Я сделал три картинки и поместил их в ресурсы приложения. Для обозначения границ «TImage», поместил «TImage» в «TRectangle».
 
Подгружаю из ресурсов:
var
  InStream: TResourceStream;
  i: integer;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if i=3 then i := 1
  else i := i+1;
  // Load image
  InStream := TResourceStream.Create(HInstance, 'Test_' + IntToStr(i), RT_RCDATA);
  try
    Image1.Bitmap.LoadFromStream(InStream);
  finally
    InStream.Free;
  end;
end;
Если мы ни чего не добавляли вручную в «MultiResBitmap», то все подгружаемые в «TImage» картинки не подстраиваются под размеры «TImage», т.е. остаются в оригинальных размерах.
post-19-0-23974200-1394355857.pngpost-19-0-47679000-1394355857.pngpost-19-0-63998200-1394355857.png
 
 
А теперь мы добавим любую картинку в «MultiResBitmap» с настройкам по умолчанию:
Например, картинку Width: 380; Height: 120.
post-19-0-95857800-1394355905_thumb.png
 
И в таком виде компилируем приложение, вот что мы получим:
post-19-0-10852000-1394355884.pngpost-19-0-31001300-1394355884.pngpost-19-0-50271300-1394355884.pngpost-19-0-66617500-1394355884.png
 
 
Как видите, теперь все картинки растягиваются по бОльшему размеру одной из сторон самой картинки, т.е. подгоняются автоматически под размеры TImage(Width: 310; Height: 150) сохраняя при этом пропорции сторон.
 
 
Вопрос: Как исправить ситуацию своими силами, т.е. сделать как при добавлении любой картинки в «MultiResBitmap», но без ручного добавления картинки? Чтобы все подгружаемые картинки сохраняли пропорции и при этом растягивались также по размерам «TImage».
 
p.s. По поводу прозрачности тема на форуме тоже есть.
 
Тестовое приложение прикладываю.TImageBitmap.zip
Изменено пользователем Infocean
Перезалил архив (без скриншотов)
Ссылка на комментарий

Рекомендуемые сообщения

  • 0

Когда вы загружаете картинку (в design time), то картинка подвергается изменениям.

Обратите внимание на вторую строчку окна редактора IDE. Там по умолчанию выбрано Custom Size. Еще есть поля Width и Height

 

Алгоритм работы при загрузке картинки в IDE примерно следующий:

  1. Если Width и Height равны 0 (по умолчанию), то эти размеры становятся равными размерам загруженной картинки поделенным на масштаб.
  2. Загружаемая картинка масштабируется таким образом чтобы соответствовать размерам Width и Height умноженным на текущий масштаб. Если картинка меньше, то она сжимается, если больше, то растягивается, а края заполняются прозрачным цветом.
  3. Все пиксели картинки которые имеют выбранный цвет TransparentColor заменяются на прозрачный черный цвет.
  4. Модифицированное таким образом изображение хранится в fmx-файле.

Т.е. размеры хранящегося в fmx-файле изображения могут отличаться от размеров исходного изображения. Если вы захотите на кнопочку 16x16 поместить 10-мегапиксельную фотку, то в fmx-файле будет хранится изображение 16x16.

 

А у Вас в примере масштабирования не происходит.

Image1.Bitmap.LoadFromStream(InStream);

Хранящееся изображение уже вписывается в границы TImage. Если оно меньше, то центрируется если больше, то сжимается с сохранением пропорций. В вашем примере в TImage вписывается исходное изображение из ресурса.

 

Вы можете поместить TImage на другой контрол и установить у неё Width и Height нужных (заведомо меньших) размеров, и установить свойство Align в Center.

 

Мне только не понятна целесообразность такого поведения. Получается в ресурсе хранятся лишние данные и всегда тратятся вычислительные ресурсы на масштабирование.
 

Ссылка на комментарий
  • 0
  • Модераторы
Здравствуйте, Сергей!
Я понимаю, что если изображение по размерам меньше TImage, то оно идёт по центру и не масштабируется до границ TImage. Но если изображение больше размеров TImage, то оно уменьшается до границ TImage с сохранением пропорций.
 
Мне же нужно чтобы изображение всегда подгонялось под размеры TImage при этом сохраняя пропорции. Если вставлять картинку с оригинальными размерами (Например: Width: 310; Height: 150), то выглядит она мелко и не соответствует размеру TImage.
 
Вот попытался сейчас изменить размеры так:
  Image1.Bitmap.Width := Trunc(Image1.Width * 1.34);
  Image1.Bitmap.Height := Trunc(Image1.Height * 1.34);
  Image1.Bitmap.LoadFromStream(InStream);

Но не сработало...

 

Может быть, у вас есть ссылки на материал, почитать?

Как вообще правильно такое реализовать (вы подскажите, в какую сторону копать, а я уже попробую сам разобраться)?

 

Ссылка на комментарий
  • 0

У TImage можно установить свойство WrapMode = Stretch. Оно будет растягивать изображение, правда без сохранения пропорций.
Вам видимо придется самостоятельно изменить размеры TImage для сохранения пропорций.

P.S. Кстати пользуясь случаем выкладываю ссылку на демо

Ссылка на комментарий
  • 0
  • Администраторы

Правильно ли я понимаю задачу:

  1. Мы делаем типа шапки приложения. И нам важно, чтобы шапка имела фиксированную высоту, а по ширине растягивалась по ширине экрана. При этом изображение шапки по ширине подгонялось по ширине экрана, а высота вычислялась автоматически с сохранением пропорции?
  2. При этом мы загружаем в шапку заведомо большее изображение, чтобы покрыть все возможные варианты ширины экрана устройства?
Ссылка на комментарий
  • 0
  • Модераторы
Ярослав,
Объясняю:
Например, на форме лежит Layout1(Align: alTop; Height: 160), на нем лежит Timage(Align: alCenter; Height: 150; Width: 310). Т.е. размеры Timage фиксированные.
Картинки, которые будут подгружаться в этот Timage не имеют каких-то стандартов по размерам, т.е. размер может быть «Height: 150; Width: 310» или «Height: 100; Width: 400». Чтобы они нормально выглядели и не мелко и не размазано, мне необходимо изменять их размеры (автоматически или через код приложения) пропорционально, подгоняя картинку под размер Timage.
 
Единственный вариант, который работает и проверен мной, описан выше. Это перед компиляцией приложения поместить любую картинку в «MultiResBitmap». Тогда любые картинки, подгружаемые в Timage (во время использования приложения), сами, автоматически, пропорционально изменяют свои размеры.
 
Использовать свойство «WrapMode: iwStretch» не вариант, т.к. большие картинки становятся сплющенными и т.п.
 
В общем, пока, буду использовать «левую» картинку, чтобы все остальные автоматически подстраивались.
Ссылка на комментарий
  • 0
  • Администраторы

"Подгонять" - это Fit, или по высоте или ширине в зависимости от пропорции изображения и пропорции TImage?

Ссылка на комментарий
  • 0

Если мы растягиваем по ширине, то что-то мы должны обрезать.
У Rectangle1 делаем ClipChildren = True
А Image1 выравниваем по вертикали по центру Align = VertCenter
В коде получаем масштаб исходя из ширины, а высоту ставим согласно полученного масштаба. В результате верхняя и нижняя части картинки может обрезаться. Если делать Align = Top, Bottom, то можно обрезать только нижнюю и только верхнюю часть картинки.

Т. е. получается что-то типа этого

  object Rectangle1: TRectangle
    Align = Top
    ClipChildren = True
    Height = 150.000000000000000000
    Margins.Left = 5.000000000000000000
    Margins.Top = 5.000000000000000000
    Margins.Right = 5.000000000000000000
    Position.X = 5.000000000000000000
    Position.Y = 5.000000000000000000
    Width = 374.000000000000000000
    object Image1: TImage
      MultiResBitmap = <
        item
        end>
      Align = VertCenter
      Height = 274.000000000000000000
      Position.Y = -62.000000000000000000
      Width = 374.000000000000000000
      WrapMode = Stretch
    end
  end
  object Button1: TButton
    Align = Top
    Height = 44.000000000000000000
    Position.Y = 155.000000000000000000
    TabOrder = 1
    Text = #1055#1086#1076#1075#1088#1091#1079#1080#1090#1100
    Width = 384.000000000000000000
    OnClick = Button1Click
  end
 
procedure TForm1.Button1Click(Sender: TObject);
var
  Scale: Single;
begin
  if i=3 then i := 1
  else i := i+1;
  Image1.BeginUpdate;
  try
    // Load image
    InStream := TResourceStream.Create(HInstance, 'Test_' + IntToStr(i), RT_RCDATA);
    try
      Image1.Bitmap.LoadFromStream(InStream);
      Scale := Image1.Width / Image1.Bitmap.Width;
      Image1.Height := Image1.Bitmap.Height * Scale;
    finally
      InStream.Free;
    end;
  finally
    Image1.EndUpdate;
    Invalidate;
  end;
end;
Ссылка на комментарий
  • 0
  • Модераторы

Ярослав, Fit срабатывает только когда изображение больше чем TImage.

Сергей, я сделал всё, как вы написали, реакции 0... Все изображения также подгружаются в исходном разрешении.

Ссылка на комментарий
  • 0
  • Администраторы

Андрей, Интересно, а каким способом вы собираетесь без изменения размера контейнера картинки вписать картинку с сохранением размеров, да еще так, чтобы она не обрезалась? Вы уж определить, что вы хотите в конечном итоге.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...