Перейти к содержанию
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
Опубликовано

Если мы растягиваем по ширине, то что-то мы должны обрезать.
У 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 пользователей онлайн

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