изображение, созданное на Cimg, отличается от pdf при сохранении с использованием GDI+ с pdf, созданным с помощью jagPDF

То, что мне нужно сделать, очень просто: мне нужно построить вектор с помощью CIMG, а затем сохранить график в формате jpg и добавить jpg в документ PDF с помощью JAGPDF. Чтобы сохранить CIMG в формате JPG, программа использует внешнюю программу под названием Image Magick.

Я хотел избежать использования этой программы и использовать GDI+ вместо этого сначала сохраните CIMG как BMP (он делает это изначально), а затем сохраните jpg из bmp.

Программа MCVE выглядит так

#include "CImg.h"
#include <jagpdf/api.h>
#include <vector>

using namespace jag;
using namespace cimg_library;

int main(int argc, char** const argv)
{

    const float x0 = 0;
    const float x1 = 9;
    const int resolution = 5000;

    // Create plot data.
    CImg<double> values(1, resolution, 1, 1, 0);

    const unsigned int r = resolution - 1;

    for (int i1 = 0; i1 < resolution; ++i1)
    {
        double xtime = x0 + i1*(x1 - x0) / r;
        values(0, i1) = 2 * sin(xtime);
    }

    CImg<unsigned char> graph;
    graph.assign(750, 240, 1, 3, 255);

    static const unsigned char black[] = { 0, 0, 0 }, white[] = { 255, 255, 255 };
    static const unsigned char red[] = { 255, 200, 200 }, bred[] = { 255, 0, 0 };

    graph.draw_grid(6, 6, 0, 0, false, true, red, 10.0f, 0xFFFFFFFF, 0xFFFFFFFF);
    graph.draw_grid(30, 30, 0, 0, false, true, bred, 10.0f, 0xFFFFFFFF, 0xFFFFFFFF);

    graph.draw_graph(values, black, 1, 1, 1, 2, -2, 0xFFFFFFFF);;

    //////////////Method 1: Using Image Magick////////////////
    graph.save_jpeg("plot2.jpg");

    pdf::Document doc(pdf::create_file("report.pdf"));
    doc.page_start(848.68, 597.6);
    pdf::Image imag2 = doc.image_load_file("plot2.jpg");
    doc.page().canvas().image(imag2, 50, 50);
    doc.page_end();
    doc.finalize();
    //////////////Method 2: Using GDI+////////////////
    graph.save("plot.bmp");
    SaveFile();
    pdf::Document doc2(pdf::create_file("report2.pdf"));
    doc2.page_start(848.68, 597.6);
    pdf::Image imag = doc2.image_load_file("plot.jpg");
    doc2.page().canvas().image(imag, 50, 50);
    doc2.page_end();
    doc2.finalize();

    return 0;
}

С SaveFile(), являющимся следующей функцией, использующей GDI+ для преобразования из plot.bmp в plot.jpg

#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#include "GdiplusHelperFunctions.h"


#pragma comment (lib,"Gdiplus.lib")

VOID SaveFile()
{
    // Initialize GDI+.
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    CLSID   encoderClsid;
    Status  stat;
    Image*   image = new Gdiplus::Image(L"plot.bmp");

    // Get the CLSID of the PNG encoder.
    GetEncoderClsid(L"image/jpeg", &encoderClsid);

    stat = image->Save(L"plot.jpg", &encoderClsid, NULL);

    if (stat == Ok)
        printf("plot.jpg was saved successfully\n");
    else
        printf("Failure: stat = %d\n", stat);

    delete image;
    GdiplusShutdown(gdiplusToken);
    }

Оба метода сохраняют jpg, которые в свойствах имеют одинаковый размер, но первый правильно помещает изображение в pdf, а второй помещает огромное изображение в pdf, даже если они должны быть одинакового размера. Как я могу это исправить?

Прикрепил скриншоты report1 и report2

введите здесь описание изображения

введите здесь описание изображения

РЕШЕНИЕ

С вашими предложениями я смог изменить функцию SaveFile, чтобы иметь возможность контролировать DPI, я публикую новый код на случай, если он кому-то понадобится.

VOID SaveFile()
{
    // Initialize GDI+.
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    CLSID   encoderClsid;
    Status  stat;
    EncoderParameters encoderParameters;
    ULONG    quality;

    Gdiplus::Bitmap*   bitmap = new Gdiplus::Bitmap(L"plot.bmp");
    Gdiplus::REAL dpi = 96;
    bitmap->SetResolution(dpi,dpi);


    // Get the CLSID of the PNG encoder.
    GetEncoderClsid(L"image/jpeg", &encoderClsid);

    encoderParameters.Count = 1;
    encoderParameters.Parameter[0].Guid = EncoderQuality;
    encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
    encoderParameters.Parameter[0].NumberOfValues = 1;

   quality = 100;
   encoderParameters.Parameter[0].Value = &quality;

   stat = bitmap->Save(L"plot.jpg", &encoderClsid, &encoderParameters);


   if (stat == Ok)
        printf("plot.jpg was saved successfully\n");
   else
        printf("Failure: stat = %d\n", stat);

   delete bitmap;
   GdiplusShutdown(gdiplusToken);
   return;
}

person Diego Fernando Pava    schedule 27.09.2016    source источник


Ответы (2)


Я предполагаю, что ImageMagick включает в себя некоторые льготы, которые фильтруют изображение, чтобы оно соответствовало холсту. Умница. Я бы попробовал изменить размер изображения перед экспортом в JPEG. Вы можете воспользоваться этим руководством. По сути, это говорит о том, что вы можете изменить размер bmp (в примере проверяется соотношение w/h, но…). Цель должна заключаться в том, чтобы указать размер, который вам нужен для холста, именно такой.

Gdiplus::Bitmap* GDIPlusImageProcessor::ResizeClone(Bitmap *bmp, INT width, INT height)
{
    UINT o_height = bmp->GetHeight();
    UINT o_width = bmp->GetWidth();
    INT n_width = width;
    INT n_height = height;
    double ratio = ((double)o_width) / ((double)o_height);
    if (o_width > o_height) {
        // Resize down by width
        n_height = static_cast<UINT>(((double)n_width) / ratio);
    } else {
        n_width = static_cast<UINT>(n_height * ratio);
    }
    Gdiplus::Bitmap* newBitmap = new Gdiplus::Bitmap(n_width, n_height, bmp->GetPixelFormat());
    Gdiplus::Graphics graphics(newBitmap);
    graphics.DrawImage(bmp, 0, 0, n_width, n_height);
    return newBitmap;
}

А затем сохраните его с помощью энкодера. Кроме того, вы хотели бы проверить, может ли вам потребоваться установить качество результирующего JPEG с помощью параметров кодировщика, как показано в официальном документация.

// Get the CLSID of the JPEG encoder.
   GetEncoderClsid(L"image/jpeg", &encoderClsid);

   // Before we call Image::Save, we must initialize an
   // EncoderParameters object. The EncoderParameters object
   // has an array of EncoderParameter objects. In this
   // case, there is only one EncoderParameter object in the array.
   // The one EncoderParameter object has an array of values.
   // In this case, there is only one value (of type ULONG)
   // in the array. We will let this value vary from 0 to 100.

   encoderParameters.Count = 1;
   encoderParameters.Parameter[0].Guid = EncoderQuality;
   encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
   encoderParameters.Parameter[0].NumberOfValues = 1;

   // Save the image as a JPEG with quality level 0.
   quality = 0;
   encoderParameters.Parameter[0].Value = &quality;
   stat = image->Save(L"Shapes001.jpg", &encoderClsid, &encoderParameters);

   if(stat == Ok)
      wprintf(L"%s saved successfully.\n", L"Shapes001.jpg");
   else
      wprintf(L"%d  Attempt to save %s failed.\n", stat, L"Shapes001.jpg");

   // Save the image as a JPEG with quality level 50.
   quality = 50;
   encoderParameters.Parameter[0].Value = &quality;
   stat = image->Save(L"Shapes050.jpg", &encoderClsid, &encoderParameters);

   if(stat == Ok)
      wprintf(L"%s saved successfully.\n", L"Shapes050.jpg");
   else
      wprintf(L"%d  Attempt to save %s failed.\n", stat, L"Shapes050.jpg");

РЕДАКТИРОВАТЬ: JAGPDF также говорит, что DPI изображения учитывается при рисовании. Так что, наверное, мы на правильном пути.

Допустим, мы хотели бы замостить область страницы нашим изображением. Для этого нам нужно знать размеры изображения. Поскольку width() и width() возвращают размер в пикселях, нам нужно пересчитать их в единицы пользовательского пространства. DPI изображения учитывается, когда изображение наносится на холст. Изображение обычно указывает свой DPI. Если это не так, используется значение images.default_dpi.

img_width = img.width() / img.dpi_x() * 72
img_height = img.height() / img.dpi_y() * 72
for x in range(7):
    for y in range(15):
        canvas.image(img, 90 + x * img_width, 100 + y * img_height)

Вы можете попробовать изменить DPI, используя этот Так ответьте.

person Alfabravo    schedule 27.09.2016
comment
Большое спасибо за вашу помощь, я наконец смог изменить настройку DPI с вашими предложениями. - person Diego Fernando Pava; 27.09.2016

Если я правильно понял ваш вопрос, ваша цель — удалить зависимость от ImageMagick.

Вы можете сделать это проще, сказав CImg использовать встроенную поддержку JPEG. Все, что вам нужно сделать, это

  • определить cimg_use_jpeg
  • ссылка с libjpeg

Таким образом, ваша команда компиляции становится:

g++ -Dcimg_use_jpeg ... -ljpeg
person Mark Setchell    schedule 27.09.2016