Что нового

[Математика] Как расположить картинки в HTML в 2 ряда ?

vaf

Новичок
Сообщения
190
Репутация
2
Доброго времени суток уважаемые форумчане. Всех с прошедшим новым годом, рождеством и наступающим старым. У меня очередная (пока для меня не разрешимая) проблема
В общем суть в следующем. Задумал я сделать скрипт который бы мне вписывал все картинки в определенную ширину, при этом чтобы высота у них была одинаковая, т.е. красивое расположение картинок в один ряд.
Как я решил эту задачу: Допустим есть массив из нескольких картинок разного размера. Нужно все их в вписать в нужную нам ширину, а чтобы не получился забор, нужно чтобы высота всех была одинаковая.
Делал я это так. С помощью _GDIPlus_ImageGetDimension я узнавал ширину и высоту каждой картинки в массиве. Далее в цикле от 1 и до тех пор пока общая ширина не будет равна нужной, я прибавлял высоту всех картинок и высчитывал полученную ширину
как только общая ширина равнялась нужной мне, я делал выход из цикла, а текущее значение цикла и было нужной мне высотой.
потом формировал HTML сроку, к примеру
Код:
<a href="http://site.ru/wp-content/uploads/_iyltz-fmg0.jpg"><img class="alignright" title="_iyltz-fmg0.jpg" src="/wp-content/uploads/_iyltz-fmg0.jpg" alt="" height="52" /></a><a href="http://site.ru/wp-content/uploads/qepeet1a8nq.jpg"><img class="alignright" title="qepeet1a8nq.jpg" src="/wp-content/uploads/qepeet1a8nq.jpg" alt="" height="52" /></a><a href="http://site.ru/wp-content/uploads/hizj9fz-iqk.jpg"><img class="alignright" title="hizj9fz-iqk.jpg" src="/wp-content/uploads/hizj9fz-iqk.jpg" alt="" height="52" /></a><a href="http://site.ru/wp-content/uploads/rfhkc-5lfre.jpg"><img class="alignright" title="rfhkc-5lfre.jpg" src="/wp-content/uploads/rfhkc-5lfre.jpg" alt="" height="52" /></a><a href="http://site.ru/wp-content/uploads/vrba-s9swpi.jpg"><img class="alignright" title="vrba-s9swpi.jpg" src="/wp-content/uploads/vrba-s9swpi.jpg" alt="" height="52" /></a><a href="http://site.ru/wp-content/uploads/cdyrhlfohd4.jpg"><img class="alignright" title="cdyrhlfohd4.jpg" src="/wp-content/uploads/cdyrhlfohd4.jpg" alt="" height="52" /></a>
где 52 как раз и есть высчитанное значение.
Все бы хорошо, если этих картинок от 1 до 4 или 5, но если их 7,8, 9 или 10 то они получались слишком мелкие. И вот теперь передо мной стоит задача. Если картинок больше 5, пусть они будут в два ряда, так же с одинаковой высотой в каждом ряду и вписанные в общую ширину.
Вот часть скрипта которая отвечает за вывод картинок в одну линию.

На входе $1 - Массив из имен всех картинок
$width - ширина в которую будем вписывать все картинки
На выходе: $y - общая высота для всех картинок.

Код:
$1 = _StringBetween($post_text,'title="','" src') ; Заносим в массив имена всех картинок
   
   $width = 600
	  
   _GDIPlus_Startup()
   For $y = 1 To 250 ; Цикл на высоту от 1 до 250 точек (чтобы максимальная высота не превышала 250 точек)
	  $tmp = 0
	  For $i = 0 To UBound ($1) - 1 ; Цикл на все картинки
		 $hImage = _GDIPlus_ImageLoadFromFile($Path & $1[$i]) ; Получаем ID картинки
		 $aSize = _GDIPlus_ImageGetDimension($hImage) ; Получаем высоту и ширину картинки $aSize[0], $aSize[1]
		 If Not IsArray ($aSize) Then
			MsgBox (4096, "Ошибка")
			Exit
		 EndIf
			
		 $nx = Floor (resize ($aSize[0], $aSize[1], $y)) ; Получаем ширину изображения для высоты Y
		 $tmp = $tmp + $nx
		 _GDIPlus_ImageDispose($hImage)
	  Next
	  If $tmp >= $width Then ExitLoop ; Если общая ширина картинок >= ширине сайта, выходим из цикла. $y = высота картинок
   Next
   _GDIPlus_ShutDown ()


Func resize ($ow, $oh, $nh) ; Функция масштабирования изображения (ширина, высота, новая высота) возвращает получившуюся ширину
   $x = (($ow * $nh) / $oh)
   Return $x
EndFunc

Есть какие нибудь идеи ?
 

idbehold

Новичок
Сообщения
42
Репутация
4
Получить 2 ряда одинаковой высоты у Вас, вряд ли, получится.
Так как для этого нужно, чтобы можно было разделить картинки на 2 равные "полоски".
Хотя в идеальных условиях, конечно, возможно.

Могу предложить алгоритм, который раскидывает картинки в наиболее одинаковые по ширине полоски.
Правда, извините, не буду описывать это на автоит.

Делаем следующее:

1) закидываем все картинки в массив
2) подгоняем размеры картинок под одинаковую высоту (любую, потом исходя из результата перерезайзим)
3) создаем 2 массива, в первом будут все картинки, кроме последней, во втором - последняя.
Назовем их leftImages и rightImages

Далее нам понадобятся 2 функции:

Первая будет принимать на вход массив и возвращать сумму длин картинок в нем.
Назовем ее getLineWidth

Вторая - рекурсивная функция, которая расположит картинки в этих двух массивах так, чтобы получить примерно наиболее одинаковые по ширине полоски.
На вход получает 2 массива, возвращает 2 массива. Назовем ее SortImages
Далее приведен псевдокод:

Функция SortImages(leftImages, rightImages):

Запоминаем модуль разности длин картинок в массивах, тут будет храниться наилучшее расхождение длин.
bestDiff = ABS(getLineWidth(leftImages) - getLineWidth(rightImages))

Копируем "левый" и "правый" массивы, тут будут лежать наилучшие "полоски" картинок, на данный момент
bestLeftArray = leftImages;
bestRightArray = rightImages;

Для каждого элемента leftImages :
Для каждого элемента rightImages :
Создадим копии левого и правого массива, это временные переменные. назовем их tmpLeftArray и tmpRightArray
В созданных копиях меняем местами текущий элемент из левого массива с текущим элементом из правого
Если модуль разности длин картинок в полученных массивах меньше, чем bestDiff То:
запомним в bestDiff новую разность.
в bestLeftArray и bestRightArray запишем tmpLeftArray и tmpRightArray.
Конец условия
Конец цикла //rightImages
Конец цикла //leftImages

Если количество элементов в leftImages больше одного То:
Создадим копии левого и правого массива, это временные переменные. назовем их tmpLeftArray и tmpRightArray
Перемещаем последний элемент левого массива в правый
Выполняем: SortImages(tmpLeftArray, tmpRightArray);
Если получаем лучший результат То:
Запишем в bestLeftArray и bestRightArray результат выполнения функции.
Конец условия
Конец условия
Вернуть: bestLeftArray, bestRightArray;
Конец Функции


В результате получим 2 массива, с более-менее одинаковой длинной картинок.
Теперь можно пропорционально изменить размер всем картинкам, подогнав "полоски" под нужную ширину.

Рекомендую Вам, данный алгоритм реализовать не на autoit а на javascript и добавить вызов в код страницы, чтобы разместить картинки как нужно. Могу скинуть реализацию алгоритма на php.

PS. Алгоритм не оптимизированный, медленный.
Если Вам нужно размещать, скажем, по 100 картинок - нужно будет придумать что-то получше.
 
Автор
V

vaf

Новичок
Сообщения
190
Репутация
2
Два ряда одинаковой высоты и не нужно. пусть высота будет разная, главное чтобы общая ширина что у первого, что и у второго была одинаковая. Да и еще - максимальное количество картинок у меня 10 (больше не бывает), т.е. максимум два ряда.
скажем так:
если до 5 то один ряд
если 6 то по 3 в каждом
если 7 то 4+3
если 8, то по 4 и т.д.

В чем у меня весь затык ?
У меня всего один цикл который высчитывает высоту картинок и мне не хотелось бы делать несколько циклов специально для 6,7,8,9 или 10 картинок. хотелось бы все это сделать поизящнее, а вот опыта пока маловато.
 

idbehold

Новичок
Сообщения
42
Репутация
4
У меня есть реализация на пхп, которая раскидывает заданное количество картинок на нужное количество "полосок".
 
Автор
V

vaf

Новичок
Сообщения
190
Репутация
2
У меня есть реализация на пхп, которая раскидывает заданное количество картинок на нужное количество "полосок".
сможешь прислать ее ? Посмотрю как реализовано.
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
idbehold,
вобщем-то неплохо. Начало алгоритма просто как по учебнику, но вот сама рекурсия как-то не того. Да и как вы собираетесь вернуть из функции два массива?
(вообще-то это сайт посвященный AutoIt, не стоит хвастаться достижениями в других ЯП)

vaf,
вот что у меня получилось. Если комментариев недостаточно, задавайте вопросы, поясню что к чему.
Код:
#Include <Array.au3>

$1 = _StringBetween($post_text,'title="','" src') ; Заносим в массив имена всех картинок
   
Global $width = 600 ; ширина панорамы
Global $aSizeX[UBound($1)] ; временный массив - ширина картинок после масштабирования под эталон

_GDIPlus_Startup()   

#cs
Получаем высоту первой картинки и принимаем её за эталон
#ce
$hImage = _GDIPlus_ImageLoadFromFile($Path & $1[$i]) ; Получаем ID картинки
$aSize = _GDIPlus_ImageGetDimension($hImage) ; Получаем высоту и ширину картинки $aSize[0], $aSize[1]
If Not IsArray ($aSize) Then
	MsgBox (4096, "Ошибка")
	Exit
EndIf

Global $eSizeY = $aSize[1]

#cs
В массив $aSizeX заносим ширину всех картинок после масштабирования
попутно суммируя ширину всех картинок после масштабирования
#ce
$aSizeX[0] = $aSize[0]
Global $sumX = $aSizeX[0]

For $i = 1 To UBound ($1) - 1 ; Цикл на все картинки
    $hImage = _GDIPlus_ImageLoadFromFile($Path & $1[$i]) ; Получаем ID картинки
    $aSize = _GDIPlus_ImageGetDimension($hImage) ; Получаем высоту и ширину картинки $aSize[0], $aSize[1]
	If Not IsArray ($aSize) Then
		MsgBox (4096, "Ошибка")
		Exit
	EndIf
	$aSizeX[$i] = resize ($aSize[0], $aSize[1], $eSizeY ) ; Получаем ширину изображения для высоты эталона
	$sumX += $aSizeX[$i]
	_GDIPlus_ImageDispose($hImage)
Next
_GDIPlus_ShutDown ()

#cs
Ищем такой набор картинок, чтобы его ширина была наиболее близка к половине ширины всех картинок
#ce
Global $sumX_2 = Floor($sumX/2) ; Ширина одного ряда 
Global $strBestRes = "" ; набор картинок хранится как строка индексов картинок, разделённых запятыми
Global $BestLength = 0 ; наилучшая найденная ширина набора картинок


calculate(String($aSizeX[0])) ; старт рекурсии, начиная с самой первой картинки

$BestLength = _max($BestLength, $sumX-$BestLength)

$mSizeY = resize ($eSizeY, $width, $BestLength) ; пересчёт эталона высоты картинок, так чтобы ширина ряда равнялась заданной ширине панорамы

MsgBox(0, "лучший результат", "оптимальный первый ряд картинок:"&$strBestRes&@CR&"при высоте картинок = "&$mSizeY)

Func calculate($strGrup1) ; рекурсивная функция перебора картинок
	Local $aGrup1 = StringSplit($strGrup1, ",", 2)
	Local $sum = 0
	For $i = 0 To UBound($aGrup1)-1
		$sum += Number($aGrup1[$i]) ; пересчёт суммы ширины картинок в наборе
	Next
	If Abs($sum - $sumX_2) < Abs($BestLength - $sumX_2) Then ; если ширина набора лучше чем раннее найденная, то сохраняем лучший результат
		$strBestRes = $strGrup1
		$BestLength = $sum
	EndIf
	If $sum >= $sumX_2 Then Return
	If UBound($aGrup1) = UBound($aSizeX) Then Return
	
	For $i = 1 To UBound($aSizeX)-1
		If _ArraySearch($aGrup1,$i) = -1 Then calculate( $strGrup1 & "," & $i ) ; если $i-тая картинка ещё не в наборе, то добавляем её в набор и делаем рекурсивный вызов
	Next
EndFunc

Func resize ($ow, $oh, $nh) ; Функция масштабирования изображения (ширина, высота, новая высота) возвращает получившуюся ширину
   $x = Floor (($ow * $nh) / $oh)
   Return $x
EndFunc
 

idbehold

Новичок
Сообщения
42
Репутация
4
Понимаю, что форум по автоит.
Предложил php решение, потому что это лучше чем разбирать псевдокод.
Да и на автоите я бы это не реализовал. Точнее, это заняло бы у меня не один час.

Файлик прикрепляю, пощелкать можно тут. http://idbeholdl.ts9.ru/demo/
 
Автор
V

vaf

Новичок
Сообщения
190
Репутация
2
idbehold
Круто. Глаза разбегаются от кол-ва строк.

C2H5OH
А у меня возникла вот какая идея. т.к. у меня максимальное количество картинок 10, то можно сделать так. Делаем вложенный цикл первый цикл будет отвечать за кол-во строк (у меня 2), а вложенный в него цикл за их обработку.
Если картинок до 4, то первый цикл исполняться не будет, обрабатываем как в моем скрипте, что я приводил в первом посте). Если кол-во картинок скажем 7, то первый цикл сработает два раза. один раз для 1,2,3,4 картинки и второй раз для 5,6,7 картинки.
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Ты не можешь утверждать что общее количество картинок разбивается на два ряда пополам.
Теоретически допустима ситуация что первый ряд состоит из одной картинки, а второй из всех остальных.
 

idbehold

Новичок
Сообщения
42
Репутация
4
Вот именно. Нужно еще и перетаскивать картинки из одного массива в другой.
Ладно, думаю автор темы реализует то, что хотел.
А можете рассказать куда вы потом эти картинки вставлять будете?
 
Автор
V

vaf

Новичок
Сообщения
190
Репутация
2
А можете рассказать куда вы потом эти картинки вставлять будете?
автоматизированная генерация HTML страниц для сайта. Ручками долго, хотелось бы автоматизировать, все уже сделал, осталось только картинки расположить.
 
Верх