Сохранение файла в gdi+

Тема в разделе "LANGS.C", создана пользователем _qwe8013, 5 дек 2016.

  1. _qwe8013

    _qwe8013 Active Member

    Публикаций:
    2
    Регистрация:
    30 ноя 2016
    Сообщения:
    123
    Понадобилось мне тут сохранить созданный в памяти Bitmap в gif, поступил следующим образом:
    Нашёл в гугле процедуру получения CLSID кодека:
    Код (C):
    1. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
    2. {
    3.     UINT  num = 0;          // number of image encoders
    4.     UINT  size = 0;         // size of the image encoder array in bytes
    5.  
    6.     Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;
    7.  
    8.     GetImageEncodersSize(&num, &size);
    9.     if (size == 0)
    10.         return -1;  // Failure
    11.  
    12.     pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
    13.     if (pImageCodecInfo == NULL)
    14.         return -1;  // Failure
    15.  
    16.     GetImageEncoders(num, size, pImageCodecInfo);
    17.  
    18.     for (UINT j = 0; j < num; ++j)
    19.     {
    20.         if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
    21.         {
    22.             *pClsid = pImageCodecInfo[j].Clsid;
    23.             free(pImageCodecInfo);
    24.             return j;  // Success
    25.         }
    26.     }
    27.  
    28.     free(pImageCodecInfo);
    29.     return -1;  // Failure
    30. }
    Вызвал её так:
    Код (C):
    1. CLSID CODCLSID;
    2.     int index = GetEncoderClsid(L"image/gif", &CODCLSID);
    3.     if (index == -1)
    4.     {
    5.         printf("Can not get encoder CLSID!\n");
    6.         getchar();
    7.         return 0;
    8.     }
    Всё отработало нормально. Далее выделил память и пока-что забил её нулями:
    Код (C):
    1.  
    2. #define PIC_SIZE 500
    3. ...
    4. RGBQUAD *BitmapData = (RGBQUAD*)malloc(PIC_SIZE*PIC_SIZE*sizeof(RGBQUAD));
    5.     ZeroMemory(BitmapData, PIC_SIZE*PIC_SIZE*sizeof(RGBQUAD));
    Ну, и в конце создал bitmap на основе BitmapData и попытался сохранить:
    Код (C):
    1. Bitmap bm(PIC_SIZE, PIC_SIZE, INT(0), PixelFormat32bppPARGB, (BYTE*)BitmapData);
    2.     Stat = bm.Save(L"C:\\temp\\test.gif", &CODCLSID);
    В итоге Stat принемает значение InvalidParameter и файл не сохраняется.
    Вопрос как говорится в следующем: "в каком коде ошибка?", только не говорите, что в генетическом.
     
    Mikl___ нравится это.
  2. _edge

    _edge Well-Known Member

    Публикаций:
    1
    Регистрация:
    29 окт 2004
    Сообщения:
    631
    Адрес:
    Russia
    Привет. Сразу скажу, в Си плоховат, но есть несколько вопросов,

    - вызов bm.Save - есть возможность показать код функции Save? в приведенных исходниках его не видно.
    - есть возможность вызвать Save не для bm, а для другого куска памяти, ради теста, пусть для строки "1234567890" ?

    Сущность Save слишком размыта, чтобы сходу понять, почему возникает ошибка.
    InvalidParameter может относиться как к неверно переданным параметрам при вызове Save, так и быть следствием какой-то внутренней нестыковки (напр. оно может делать запись только в существующий файл; при попытке обратиться к несуществующему файлу она не создает его, и возвращает ошибку)
     
  3. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.329
    Это же просто метод COM-интерфейса Image::Save(). Вообще, с выходом семерки, первый вопрос, который возникает при виде путей вида "C:\\..." - а есть ли права на запись?
     
  4. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.329
    И продолжаю, натолкнув самого себя на мысль :)
    Раз это COM, то использовать надо BSTR. Это не совсем то же самое, что и обычная юникод-строка, там счетчик длины еще есть по отрицательному смещению.
     
  5. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    861
    У тебя некорректная величина stride. Для твоего примера она должна быть равна 4 * PIC_SIZE.
     
    Mikl___ и _qwe8013 нравится это.
  6. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    861
    Это не COM интерфейс.
     
    Mikl___ нравится это.
  7. _qwe8013

    _qwe8013 Active Member

    Публикаций:
    2
    Регистрация:
    30 ноя 2016
    Сообщения:
    123
    Действительно, тупанул с параметром stride теперь всё работает.
    Это просто обёртка над вполне обычной функцией из gdiplus.dll и как я понимаю никакой не COM:
    Код (C++):
    1. inline Status
    2. Image::Save(
    3.     IN const WCHAR* filename,
    4.     IN const CLSID* clsidEncoder,
    5.     IN const EncoderParameters *encoderParams
    6.     )
    7. {
    8.     return SetStatus(DllExports::GdipSaveImageToFile(nativeImage,
    9.                                                      filename,
    10.                                                      clsidEncoder,
    11.                                                      encoderParams));
    12. }
     
    Mikl___ нравится это.