" title="Написать письмо">Написать письмо

Статистика

Пользователи : 1
Статьи : 1948
Просмотры материалов : 7069478
 
О пространственном мышлении (14.10.2022). Печать E-mail
2022 - Октябрь
14.10.2022 17:49
Save & Share
Пространственное воображение - совокупность других пространственных сущностей. Например, путаница, где лево и право - отсутствие пространственной ориентации. Ремонт в квартире показал, что еще один подвид, глазомер, - кое-какой имеется. А вот переход на новую работу и работа с картами - показали отсутствие пространственного мышления на плоскости (что будет в объеме - подумать страшно). В итоге, тривиальная задача обернулась кошмаром.


Дано:
- лист А4;
- на листе всегда есть один рисунок и следующая за ним одна таблица с известным количеством строк. Они не должны вместе занимать больше одной страницы;
- рисунок всегда вписан в холст (максимально возможную ширину и высоту для занимания изображением). Пропорции изображения при вставке в холст не должны изменяться;
- размеры-формы холста и изображения хаотичны от страницы к странице - но фиксированы для конкретной страницы;
- высота таблицы меняется от страницы к странице - но фиксирована для конкретной страницы;
- размер шрифта может быть изменен в любой момент - но фиксирован для конкретной страницы и ее таблицы;
- известны отступы при печати страницы на принтере.

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

Осложнения: тройная конвертация исходного кода страницы для принтера, ввиду забагованных ОС Astra Linux и среды программирования Qt v.5.3. Это выражается в:
- самовольном преобразовании HTML-кода элементами textEdit и textBrowser (вставил в них одно - считал из них другое);
- самовольном преобразовании преобразованного HTML-кода при сохранении в PDF;
- самовольном преобразовании PDF-документа программой qpdfview (неправильное отображение относительно принтера);
- глюки шрифтов. Например, использование шрифта "Verdana" порождает на распечатанном листе лишний целый пробел после буквы "ж" и лишние пол-пробела после буквы "л" - в полиячеечных таблицах.

Осложнения 2, ввиду забагованных ОС Astra Linux и среды программирования Qt v.5.3:
- работают не все теги стандартного HTML;
- не работают CSS и слои.

Часть с таблицей проста. Сохранять увеличиваемое количество ячеек таблицы в PDF до тех пор, пока количество страниц PDF-документа не изменится с 1 на 2. Зная количество ячеек на страницу и высоту страницы в пикселях (минус отступы в пикселях) - известно количество пикселей на строку. Значит, известна оставшаяся высота в пикселях для холста изображения. Ширина холста в пикселях определяется шириной страницы в пикселях, минус отступы, минус 4 пикселя (определяется экспериментально).

А вот правильно вставить изображение в холст - это шибанешься. Проблема не в придумывании формул, а в проверке их правильности. Изображение может быть больше и меньше холста, иметь разные пропорции. И никто не отменял масштабирования изображения в холсте: например, изображение 23000x13000 пикселей - оптимально войдет в холст 230x130 пикселей.

Придуманный данный короткий вариант - требовал проверки:

const double dProportion_XY_Canvas = 1.0*iCanvas_X_Max/iCanvas_Y_Max; //Пропорция сторон холста.
const double dProportion_XY_Picture = 1.0*iPicture_Width/iPicture_Height; //Пропорция сторон изображения.

if (dProportion_XY_Picture >= dProportion_XY_Canvas) qsResult += " width=" + qsCanvas_X_Max; //Натянуть изображение на верхнюю грань холста - масштабирование по высоте произойдет автоматически, высота изображения не выйдет за пределы высоты холста.
else qsResult += " height=" + qsCanvas_Y_Max; //Натянуть изображение на боковую грань холста - масштабирование по ширине произойдет автоматически, ширина изображения не выйдет за ширину холста.


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

            const QString qsCanvas_X_Max = "639"; //При печати: пикселей в миллиметре - 3.457шт. Соответствует ширине листа A4 210мм, минус края 24мм, минус 4 пикселя (почему они лишние - неясно).
            const QString qsCanvas_Y_Max = "300"; //При печати: чтобы таблица с максимально возможным количеством строк, идущая после рисунка, не уехала на другой лист. Т.о., на каждую зону - свой отдельный лист.
           
            //Нужен анализ, как правильно поместить изображение в холст - чтобы его отображение было максимально большим, не растянутым и не обрезанным.
            const int iCanvas_X_Max = qsCanvas_X_Max.toInt();
            const int iCanvas_Y_Max = qsCanvas_Y_Max.toInt();
            const double dProportion_XY_Canvas = 1.0*iCanvas_X_Max/iCanvas_Y_Max; //Пропорция сторон холста.
            const double dProportion_XY_Picture = 1.0*iPicture_Width/iPicture_Height; //Пропорция сторон изображения.
           
            qsResult += "<br><center><img src=\"" + kv_config->dirs().tmp + "/" + strData_SQL.strBZ[i].qsBZ_Number + "заменить_на_пустоту.png\""; //Чтобы формуляр изготавливался быстро: чем больше разрешение сохраняемого рисунка - тем больше тормозит сохранение в PDF - и, как следствие, функция создания разрыва страниц.           
            //В Qt v.5.3 свойство "=auto" для width и height не работает.
             
            const double dProportion_X = 1.0*iPicture_Width/iCanvas_X_Max; //Пропорция ширин изображения и холста.
            const double dProportion_Y = 1.0*iPicture_Width/iCanvas_Y_Max; //Пропорция высот изображения и холста.           
           
            if (dProportion_XY_Picture == 1) //Изображение - квадрат.
            {
                if (dProportion_XY_Canvas == 1) qsResult += " width=" + qsCanvas_X_Max + " height=" + qsCanvas_Y_Max; //Квадрат изображения - в квадрат холста. Изображение - полностью пропорционально холсту. Ширина и высота изображения - преобразуются в ширину и высоту холста.
                else if (dProportion_XY_Canvas < 1) qsResult += " width=" + qsCanvas_X_Max; //Квадрат изображения - в вертикальный прямоугольник холста. Разместить по верхней грани холста - с автоматическим уменьшением его height.
                else if (dProportion_XY_Canvas > 1) qsResult += " height=" + qsCanvas_Y_Max; //Квадрат изображения - в горизонтальный прямоугольник холста. Разместить по боковой грани холста - с автоматическим уменьшением его width.
            }
            else if (dProportion_XY_Picture > 1) //Изображение - горизонтальный прямоугольник.
            {
                if (dProportion_XY_Canvas == 1) qsResult += " width=" + qsCanvas_X_Max; //Горизонтальный прямоугольник изображения - в квадрат холста. Разместить по верхней грани холста - с автоматическим уменьшением его height. Можно и по боковой грани холста.
                else if (dProportion_XY_Canvas < 1) qsResult += " width=" + qsCanvas_X_Max; //Горизонтальный прямоугольник изображения - в вертикальный прямоугольник холста. Разместить по верхней грани холста - с автоматическим уменьшением его height.
                else if (dProportion_XY_Canvas > 1) //Горизонтальный прямоугольник изображения - в горизонтальный прямоугольник холста. Развилка на пропорции холста и изображения.
                {
                    if (dProportion_XY_Picture == dProportion_XY_Canvas) qsResult += " width=" + qsCanvas_X_Max + " height=" + qsCanvas_Y_Max; //Изображение - полностью пропорционально холсту. Ширина и высота изображения - преобразуются в ширину и высоту холста.
                    else if (dProportion_XY_Picture < dProportion_XY_Canvas) //Изображение - уже холста. Развилка на пропроцию высоты: не превысит ли высоту холста при размещении по верхней грани холста (высота изображения в холсте увеличится).
                    {
                        if (dProportion_Y == 1) qsResult += " width=" + qsCanvas_X_Max; //Высота изображения - идентична высоте холста. Разместить по верхней грани холста - с автоматическим уменьшением его height.
                        else if (dProportion_Y < 1) qsResult += " width=" + qsCanvas_X_Max; //Высота изображения - войдет в высоту холста. Разместить по верхней грани холста - с автоматическим уменьшением его height.
                        else if (dProportion_Y > 1) qsResult += " height=" + qsCanvas_Y_Max; //Высота изображения - не войдет в высоту холста. Разместить по боковой грани холста - с автоматическим уменьшением его width.
                    }
                    else if (dProportion_XY_Picture > dProportion_XY_Canvas) //Изображение - шире холста. Развилка на пропорцию ширины: не превысит ли ширину холста при размещении по боковой грани холста (ширина изображения в холсте увеличится).
                    {
                        if (dProportion_X == 1) qsResult += " height=" + qsCanvas_Y_Max; //Ширина изображения - идентична ширине холста. Разместить по боковой грани холста - с автоматическим уменьшением его width.
                        else if (dProportion_X < 1) qsResult += " height=" + qsCanvas_Y_Max; //Ширина изображения - войдет в ширину холста. Разместить по боковой грани холста - с автоматическим уменьшением его width.
                        else if (dProportion_X > 1) qsResult += " width=" + qsCanvas_X_Max; //Ширина изображения - не войдет в ширину холста. Разместить по верхней грани холста - с автоматическим уменьшением его height.
                    }
                }
            }
            else if (dProportion_XY_Picture < 1) //Изображение - вертикальный прямоугольник.
            {
                if (dProportion_XY_Canvas == 1) qsResult += " height=" + qsCanvas_Y_Max; //Вертикальный прямоугольник изображения - в квадрат холста. Разместить по боковой грани холста - с автоматическим уменьшением его width. Можно и по верхней грани холста.
                else if (dProportion_XY_Canvas > 1) qsResult += " height=" + qsCanvas_Y_Max; //Вертикальный прямоугольник изображения - в горизонтальный прямоугольник холста. Разместить по боковой грани холста - с автоматическим уменьшением его width.
                else if (dProportion_XY_Canvas < 1) //Вертикальный прямоугольник изображения - в вертикальный прямоугольник холста. Развилка на пропорции холста и изображения.
                {
                    if (dProportion_XY_Picture == dProportion_XY_Canvas) qsResult += " width=" + qsCanvas_X_Max + " height=" + qsCanvas_Y_Max; //Изображение - полностью пропорционально холсту. Ширина и высота изображения - преобразуются в ширину и высоту холста.
                    else if (dProportion_XY_Picture < dProportion_XY_Canvas) //Изображение - уже холста. Развилка на пропроцию ширины: не превысит ли ширину холста при размещении по боковой грани холста (ширина изображения в холсте увеличится).
                    {
                        if (dProportion_X == 1) qsResult += " height=" + qsCanvas_Y_Max; //Ширина изображения - идентична ширине холста. Разместить по боковой грани холста - с автоматическим уменьшением его width.
                        else if (dProportion_X < 1) qsResult += " height=" + qsCanvas_Y_Max; //Ширина изображения - войдет в ширину холста. Разместить по боковой грани холста - с автоматическим уменьшением его width.
                        else if (dProportion_X > 1) qsResult += " width=" + qsCanvas_X_Max; //Ширина изображения - не войдет в ширину холста. Разместить по верхней грани холста - с автоматическим уменьшением его height.
                    }
                    else if (dProportion_XY_Picture > dProportion_XY_Canvas) //Изображение - шире холста. Развилка на пропорцию высоты: не превысит ли высоту холста при размещении по верхней грани холста (высота изображения в холсте увеличится).
                    {
                        if (dProportion_X == 1) qsResult += " width=" + qsCanvas_X_Max; //Высота изображения - идентична высоте холста. Разместить по верхней грани холста - с автоматическим уменьшением его height.
                        else if (dProportion_X < 1) qsResult += " width=" + qsCanvas_X_Max; //Высота изображения - войдет в высоту холста. Разместить по верхней грани холста - с автоматическим уменьшением его height.
                        else if (dProportion_X > 1) qsResult += " height=" + qsCanvas_Y_Max; //Высота изображения - не войдет в высоту холста. Разместить по боковой грани холста - с автоматическим уменьшением его width.
                    }
                }
            }


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

Но потом выяснилось, что она верна только потому, что повезло с автомасштабированием рисунка (холст из исходных данных прекращает свое существование, убиваясь интерполяцией). Если же оставить холст в таком виде, в котором он есть, - требуется совмещать центры изображения и рисунка - и плясать именно от них. А вот какие там корректные формулы для такого видения вопроса - XYZ знает. Возможно, поможет тупое перемещение рисунка на половину величины грани, на которую не натягивалось изображение, - минус половина размера изображения.

(добавлено 28.11.2022) А алгоритм-то неверный!

Нужно сделать дополнительную пропорцию при формировании итогового размера изображения в холсте. Иначе, если изображения нет, - подставляется какой-то левый значок-рисунок (судя по всему, показывающий, что изображения нет). И у этого рисунка свои размеры - соответственно, если не указывать размер второй части изображения, - все, что после такого недорисунка - поползет.

//Ускорение создания документа: создается HTML без рисунков, рисунки создаются отдельно и потом подставляются в документ.
            //При первом проходе рисунки создаются. При втором - подцепить габариты уже существующих изображений.
            if (!strData_SQL->bLoaded) bPicture_Done = bMake_Picture(i, true, &iPicture_Width, &iPicture_Height, false, false);
            else if (QFile::exists(kv_config->dirs().tmp + "/" + g_qsNumber + ".png"))
            {
                bPicture_Done = true;

                QImage qImage;
                qImage.load(kv_config->dirs().tmp + "/" + g_qsBZ_Number + ".png");

                iPicture_Height = qImage.height();
                iPicture_Width = qImage.width();
            }

            if (bPicture_Done)
            {
                //Нужен анализ, какой размер холста создавать для TextEdit, чтобы <IMG> (даже пустой) занимал ровно столько пикселей, сколько надо: для быстрого и правильного разрыва страницы при формировании формуляра.
                const int iCanvas_X_Max = 639; //При печати: пикселей в миллиметре - 3.457шт. Соответствует ширине листа A4 210мм, минус края 24мм, минус 4 пикселя (почему они лишние - неясно).
                const int iCanvas_Y_Max = 365; //При печати: чтобы таблица с максимально 30 строками, идущая после рисунка, не уехала на другой лист. Т.о., на каждую сущность - свой отдельный лист.

                //Нужен анализ, как правильно поместить изображение в холст - чтобы его отображение было максимально большим, не растянутым и не обрезанным.
                const double dProportion_XY_Canvas = 1.0*iCanvas_X_Max/iCanvas_Y_Max; //Пропорция сторон холста.
                const double dProportion_XY_Picture = 1.0*iPicture_Width/iPicture_Height; //Пропорция сторон изображения.
               
                //Для <IMG> нужно указывать и высоту тоже. Иначе при пустом изображении в принтер помещается значок отсутствующего рисунка, размеры которого иные - высота искажается - текст съезжает - создание разрыва страницы работает неправильно.
                const double dProportion_XX = 1.0*iCanvas_X_Max/iPicture_Width;
                const double dProportion_YY = 1.0*iCanvas_Y_Max/iPicture_Height;

                qsResult += "<br><center><img src=\"" + kv_config->dirs().tmp + "/" + g_qsBZ_Number + "заменить_на_пустоту.png\""; //Чтобы формуляр изготавливался быстро: чем больше разрешение - тем больше тормозит сохранение в PDF - и, как следствие, функция создания разрыва страниц.

                if (dProportion_XY_Picture >= dProportion_XY_Canvas) qsResult += " width=" + QString::number(iCanvas_X_Max) + " height=" + QString::number(round(iPicture_Height*dProportion_XX));
                else qsResult += " width=" + QString::number(round(iPicture_Width*dProportion_YY)) + " height=" + QString::number(iCanvas_Y_Max);

                qsResult += "></img></center><br>";
Обновлено ( 28.11.2022 09:30 )
 
 

Последние новости


©2008-2024. All Rights Reserved. Разработчик - " title="Сергей Белов">Сергей Белов. Материалы сайта предоставляются по принципу "как есть". Автор не несет никакой ответственности и не гарантирует отсутствие неправильных сведений и ошибок. Вся ответственность за использование материалов лежит полностью на читателях. Размещение материалов данного сайта на иных сайтах запрещено без указания активной ссылки на данный сайт-первоисточник (ГК РФ: ст.1259 п.1 + ст.1274 п.1-3).

Много статей не имеет срока устаревания. Есть смысл смотреть и 2011, и даже 2008 год. Политика сайта: написать статью, а потом обновлять ее много лет.
Открыта карта ВТБ для донатов на дорогостоящие эксперименты: 5368 2902 0040 0838.

Рекламодателям! Перестаньте спамить мне на почту с предложениями о размещении рекламы на этом сайте. Я никогда спамером/рекламщиком не был и не буду!
Top.Mail.Ru