Уменьшить изображение в C

Здравствуйте, коллеги-программисты. Я новичок на форуме, поэтому, пожалуйста, будьте терпеливы.

Чего я пытаюсь достичь, так это взять загруженное изображение из файла (например, фоновое изображение обоев 4000x2250) и уменьшить его до собственного разрешения 1360x768. Точно так же, как в современной ОС вы устанавливаете изображение обоев для рабочего стола.

typedef struct {
    UINT8 Blue;
    UINT8 Green;
    UINT8 Red;
    UINT8 Reserved;
} EFI_GRAPHICS_OUTPUT_BLT_PIXEL;

typedef EFI_GRAPHICS_OUTPUT_BLT_PIXEL   GUI_PIXEL;

typedef struct {
    UINT32    Width;
    UINT32    Height;
    BOOLEAN   HasAlpha;
    GUI_PIXEL *PixelData;
} GUI_IMAGE;
GUI_IMAGE* ReduceImage(GUI_IMAGE* image)
{
    UINT32 resizeWidth = image->Width / 2;
    UINT32 resizeHeight = image->Height / 2;
    UINT32 x;
    UINT32 y;
    UINT32 row = 0;
    UINT32 column = 0;
    GUI_IMAGE *NewImage;

    NewImage = AllocateZeroPool(sizeof(GUI_IMAGE));
    if (NewImage == NULL)
    {
        return NULL;
    }

    NewImage->PixelData = AllocateZeroPool(resizeWidth * resizeHeight *
sizeof(GUI_PIXEL));
    if (NewImage->PixelData == NULL) 
    {
        FreePool(NewImage);
        return NULL;
    }

    NewImage->Width = resizeWidth;
    NewImage->Height = resizeHeight;
    NewImage->HasAlpha = TRUE;

    for(y = 0; y < resizeHeight - 1; y++)
    {
        for(x = 0; x < resizeWidth - 1; x++)
        {
            NewImage->PixelData[(resizeWidth) * y + x] = image->PixelData[(image->Width) * row + column];
            column += 2;
        }
        row += 2;
        column = 0;
    }

    return NewImage;
}

«на экране отображается обрезанное изображение» -> происходит ли это, когда изображение целевого размера совпадает с оригиналом?

chux - Reinstate Monica 25.07.2024 07:27
void ReduceImage( ..., GUI_IMAGE* result,... Большой красный флаг... Вызывающий объект не имеет доступа к буферу, выделенному в этой функции... Вероятно, нужен двойной указатель, но представленного кода недостаточно, чтобы точно знать, что происходит...
Fe2O3 25.07.2024 07:30

@ chux - Восстановить Монику - код написан так, чтобы запускаться только в том случае, если ширина/высота исходного изображения больше целевой высоты ширины...

Mike Ambrose 25.07.2024 23:31

@ Fe2O3 — результат GUI_IMAGE* на самом деле является глобальным в моем файле C, если это помогает.

Mike Ambrose 25.07.2024 23:33

То, как вы вызываете ReduceImage(), действительно важно (и не показано?) из-за параметров targetWidth и targetHeight . . . они действительно должны быть меньше ширины и высоты исходного изображения соответственно. Они также должны быть в пределах. Я знаю, что это элементарно, и велика вероятность, что вам это небезразлично, но… . . это будет моя первая проверка в духе перехода от простого к сложному методу отладки.

greg spears 26.07.2024 05:28

@ Грег Спирс — Мой вызов — «ReduceImage(LoadedImageFromFile(например, *.jpeg, *.png, *.bmp), GlobalImage, NativeWidth, NativeHeight); Все загруженные изображения намеренно больше исходного разрешения экрана. Я изменил часть кода, что устранило зависание, но конечным результатом является шестнадцатеричное значение без заголовка и конца, что делает изображение неотображаемым.

Mike Ambrose 26.07.2024 05:35

@Mike «Результат GUI_IMAGE* на самом деле является глобальным». Это не имеет значения. Переменная параметра с тем же именем затеняет глобальную переменную. (Распечатайте оба адреса (%p), чтобы увидеть разницу.) Локальная переменная (параметр) используется внутри тела функции, НЕ оказывая НИКАКОГО влияния на значение «глобальной» переменной... Быстрое решение: удалите этот параметр из функции сбор и использовать только «глобальную» переменную... Нехорошо, но на данный момент это исправит этот код...

Fe2O3 26.07.2024 06:25

@Fe2O3 — Внес изменения в код согласно вашему предложению, однако результат тот же… Изображение представляет собой искаженную визуализацию ширины экрана на 0,5 дюйма площади пикселя.

Mike Ambrose 27.07.2024 02:13

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

Fe2O3 27.07.2024 02:18

@MikeAmbrose Прочтите и подумайте об этих недавних вопросах и ответах. Позиция: ваше исходное изображение имеет размер 1000x1000, а вы хотите, чтобы оно было 100x100. Как написано, этот код выполнит 10^6 циклов, чтобы получить 10^4 пикселей. Не хорошо. Представьте себе, что циклы заполняют каждый целевой пиксель, вычисляя, какой исходный пиксель используется... Хотя это будет быстро, исключение 99% циклов (в этом примере) было бы целесообразным, не так ли?

Fe2O3 27.07.2024 06:16

@ Fe2O3 Fe2O3 — я переписал всю функцию с нуля, и она отлично работает, уменьшая изображение вдвое. Мой следующий вопрос: как я могу оптимизировать код для скорости и как я могу написать его, чтобы уменьшить изображение до разрешения экрана?

Mike Ambrose 27.07.2024 07:07

@MikeAmbrose Код выглядит лучше (хотя и не видит всего). Как масштабировать? Положите две линейки рядом, одна — «см», а другая — «дюймы»… Изучите, где совпадают значения «целого числа», и подумайте, как вы масштабируете, чтобы получить 12 дюймов из 30 см. Обе оси x и y прямоугольника src и dst будут иметь свой собственный «коэффициент масштабирования». Это базовая математика со школьных времен. Чтобы получить dst-пиксель для 1 дюйма, используйте src-пиксель на расстоянии 2,56 см. Поскольку есть только пиксели 2 и 3, вам нужно округлить и взять src-пиксель №3. Промыть, прополоскать, повторить... Оптимизация не является задачей беспокойство, пока все не заработает.

Fe2O3 27.07.2024 08:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
12
127
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Спасибо за всю помощь! Я понял.

#define RoundValue(x)  ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))

GUI_IMAGE* ScaleImage(GUI_IMAGE* image)
{
    float ratio; // >1 is enlarging(e.g. 1.1), <1 is reducing(e.g. 0.4)
    UINT32 resWidth;
    UINT32 resHeight;
    UINT32 x;
    UINT32 y;
    UINT32 x_in;
    UINT32 y_in;
    GUI_IMAGE *NewImage;

    GetResolution(&resWidth, &resHeight);

    ratio = (float)resWidth / (float)image->Width;

    NewImage = AllocateZeroPool(sizeof(GUI_IMAGE));
    if (NewImage == NULL)
    {
        return NULL;
    }

    NewImage->PixelData = AllocateZeroPool(resWidth * resHeight * sizeof(GUI_PIXEL));
    if (NewImage->PixelData == NULL) 
    {
        FreePool(NewImage);
        return NULL;
    }

    NewImage->Width = resWidth;
    NewImage->Height = resHeight;
    NewImage->HasAlpha = TRUE;

    for(y = 0; y < resHeight; y++)
    {
        for(x = 0; x < resWidth; x++)
        {
            x_in = RoundValue((float)x / ratio);
            y_in = RoundValue((float)y / ratio);
            NewImage->PixelData[resWidth * y + x] = image->PixelData[image->Width * y_in + x_in];
        }
    }

    return NewImage;
}

Поздравляю... Однако есть вот что, с которым код работает не совсем правильно. Вы можете решить, хотите ли вы иметь черные рамки слева/справа или сверху/снизу, ИЛИ изображение должно быть растянуто/сжато, чтобы при переключении между двумя разными «соотношениями сторон» все равно заполнялась область отображения места назначения. (Или даже «обрезать» один или два края, которые могут быть слишком широкими/высокими.) Удачи!

Fe2O3 27.07.2024 10:33

@Fe2O3 Fe2O3 - Можете ли вы показать мне, как можно реализовать, скажем, соотношение сторон 16:9 в приведенном выше коде?

Mike Ambrose 27.07.2024 18:43

Если исходное и целевое соотношение сторон 16:9, проблем нет. Аналоговые фотографии бывают разных размеров; 3x5, 4x6, 8x10... У каждого разное соотношение сторон. Поиграйтесь с любым программным обеспечением для редактирования изображений (даже с Windows Paint)... Я не могу научить вас всему в обмене комментариями здесь. Начните читать, делать заметки, исследовать и думать. Найдите здесь, на SO, «фильтр Собеля». Это не масштабирование, а манипуляция изображением. Удачи!

Fe2O3 28.07.2024 01:12

@ Fe2O3 - Спасибо за направление, отзывы, идеи и т. д. Однако немного кода для анализа или использования было бы здорово. Как указано в теме, я работаю с относительно большими изображениями, такими как обои для рабочего стола компьютера, а не с изображениями и фотографиями стандартного размера. На данный момент код не поврежден и работает, и его можно легко расширить по желанию.

Mike Ambrose 28.07.2024 01:44

Код не так уж и плох, но... Работа с плавающей запятой медленнее, чем целочисленные вычисления, И это рискует UB... 12 * 2,56 = 30,72... Если код ожидает найти «максимальный» соответствующий пиксель в 31 код будет доступен за пределами массива... Предлагаю опубликовать новый вопрос здесь или на сайте «Просмотр кода» для получения дополнительной информации. Молодец, что ты переписал и получил что-то гораздо лучшее, чем изначально! Продолжать идти!!

Fe2O3 29.07.2024 02:50

Другие вопросы по теме

Отслеживайте папку изображений, чтобы получить живую локальную галерею html/javascript
Улучшите качество подписи, извлеченной с помощью OpenCV из отсканированного листа бумаги
FileNotFoundError: [Errno 2] Нет такого файла или каталога: «C:\\Users\\User\\Downloads.png» в Python
Python – извлечение ненулевых пикселей изображения RGBA – ускорение цифровой маски
Как я могу установить собственные StartupPreferences для определенного образа Pharo?
Могу ли я отложить изображение только на мобильном устройстве, но не на компьютере?
Мой код работает только с одним файлом изображения, остальные файлы изображений считываются и сохраняются, но мой код не затрагивает их. Мне нужно, чтобы мой код работал со всеми файлами изображений
Бесшовное выравнивание фоновых изображений?
Обрезка изображения React Native
Есть ли в Javascript способ уменьшить размытие изображения поэтапно с помощью цикла и переменной?