GDI+ как работать с WINAPI

Тема в разделе "WASM.BEGINNERS", создана пользователем sivsoft, 5 май 2009.

  1. sivsoft

    sivsoft New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2008
    Сообщения:
    82
    Доброго времени суток!
    Программа на С++ под чистое WINAPI. CRT убран.
    Как можно с помощью GDI+ загрузить картинку и сохранить ее.
    Как инициализировать понятно:

    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    Непонятно как потом действовать.
    И еще как WCHAR *, который часто используется преобразовывать в char, LPSTR и обратно?
     
  2. ntcdm

    ntcdm New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2007
    Сообщения:
    247
    попробуй вот тут http://www.codeproject.com/KB/GDI-plus/gdi__and_mfc.aspx посмотреть
     
  3. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    sivsoft
    Собственно ничего сложного - берёшь любой "классовый" пример, которых в msdn много и по таблицам преобразуешь в flat версию, но это конечно извращение оправданное в асме :)), а в С++ чтобы GDI+ работало без CRT достаточно определить свои new/delete, и пару "заглушек" на некоторые заморочки, например так:
    Код (Text):
    1. //  Глобальные переменные проекта
    2. extern LPVOID activeHeap; // активная куча памяти
    3.  
    4. //  Упрощённые полезные части CRT
    5. void * __cdecl operator new(size_t n)
    6.     { return (HANDLE *)HeapAlloc(activeHeap, 0, n); }
    7. void __cdecl operator delete(void * p)
    8.     { if (p!=NULL) HeapFree(activeHeap, 0, p); }
    9.  
    10. //  Заглушки чтобы компилятор не ругался
    11. //  Константы:
    12. extern "C" const int _fltused       = 0x9876;
    13. extern "C" const int _ldused        = 0x9876;
    14.  
    15. //  Класс-заглушка RTTI сильно урезан:
    16. class type_info {
    17. public:
    18.     virtual __thiscall ~type_info() {}
    19. private:
    20.     __thiscall type_info(_In_ const type_info& _Rhs);
    21. };
    22. type_info::type_info(const type_info& rhs){};
    Это можно кинуть в любой модуль проекта или прицепить отдельным. В начале программы есно сделать: activeHeap = GetProcessHeap();
    И всё будет чудесно работать без заморочек с Flat.
     
  4. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Преобразовывать в/из unicode можно MultiByteToWideChar/WideCharToMultiByte или wsprintf(A/W) с ключём %S но может стоит подумать о полном переводе проекта на уникод?
     
  5. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.792
    sivsoft
    Преобразовывать ASCII->unicode, особенно если латиница не то, что просто, а очень просто :)
    Код (Text):
    1.   mov ah,0
    2. a1:      lodsb
    3.           stosw
    4.           test al,al
    5.           loopne a1
     
  6. sivsoft

    sivsoft New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2008
    Сообщения:
    82
    Y_Mur
    Error 15 error LNK2001: unresolved external symbol "void * activeHeap" (?activeHeap@@3PAXA) Test.obj Test
    Mikl___
    спасибо опробую :)
     
  7. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    sivsoft
    extern LPVOID activeHeap; нужно включать во все файлы где используется new/delete, остальное достаточно один раз, можно даже прицепить к проекту отдельным файлом, котрый никуда не включается - линкер разберётся.
    А в unicode кроме латиницы, есть и кириллица и спецсимволы, преобразовывать которые самому тоже можно, но имхо без особой нужды не стоит.
     
  8. sivsoft

    sivsoft New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2008
    Сообщения:
    82
    Y_Mur
    дык cpp файл у меня только один - может и в библиотечные файлы тоже?
     
  9. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Действительно глючёк :)) -один раз где нибудь activeHeap должен быть без extern.
     
  10. sivsoft

    sivsoft New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2008
    Сообщения:
    82
    Y_Mur
    Огромное спасибо - сейчас разбираю пример :)
     
  11. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Ещё одна "фишка" GDI+ - падение программы при попытках использования неудачно сконструированных шрифтов, перьев, и т.п., что наиболее неприятно в текстовых функциях, ведь шрифты могут на другом компьютере просто отсутствовать, так что не забывай проверять в программе успешность создания шрифта перед его использованием.
     
  12. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Да ещё в том примере маленький глючёк - экранный контекст тоже нужно освобождать - в этом простейшем примере это конечно произойдёт автоматически при завершении, но в общем случае конструкция Graphics graph(GetDC(0)); не удачная и её нужно заменить на:
    HDC hDC = GetDC(0);
    Graphics graph(hDC);
    ...
    ReleaseDC(0, hDC);
     
  13. sivsoft

    sivsoft New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2008
    Сообщения:
    82
    Y_Mur
    класс
    только вот не могу понять за сохранение - неужели нет функции не сохраняющей в потоке??
    я, например, пробую так загрузить файл:
    Image *img;
    if (GetOpenFileName(&ofn)==TRUE)
    {
    img->FromFile((LPCWSTR)&ofn.lpstrFile, FALSE);
    }
    а вот сохранить - там тольков stream. Или не так что делаю?
     
  14. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    У Image же есть
    Status Save( const WCHAR *filename,
    const CLSID *clsidEncoder,
    const EncoderParameters *encoderParams
    );
    Она же GdipSaveImageToFile(...) во flat версии.

    http://msdn.microsoft.com/en-us/library/ms535407(VS.85).aspx
     
  15. sivsoft

    sivsoft New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2008
    Сообщения:
    82
    Y_Mur
    написал:

    CLSID encClsid;
    GetEncoderClsid(L"image/tiff", &encClsid);
    GdipSaveImageToFile(img, "_myimage.tiff", encClsid, NULL);

    выдает:
    Error 2 error C3861: 'GdipSaveImageToFile': identifier not found c:\Documents and Settings\Siv Soft\Мои документы\Visual Studio 2008\Projects\Test\Test\Test.cpp 178 Test
     
  16. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Flat функции "спрятаны" в namespace Gdiplus::lol: llExports
    если используешь только flat замени
    #include <gdiPlus.h>
    на
    #include "GdiplusFlat.h"
    или если "смешиваешь" то уточняй namespase
     
  17. sivsoft

    sivsoft New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2008
    Сообщения:
    82
    Y_Mur
    если использовать только GdiplusFlat.h то кучу ошибок (34 штуки) выдает, одна из них:

    Error 1 error C2143: syntax error : missing ';' before '__stdcall' C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\GdiplusFlat.h 30 Test

    а если вместе использовать, то тоже самое ругается что не найдет идентификатор. :dntknw:
     
  18. sivsoft

    sivsoft New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2008
    Сообщения:
    82
    Пробую так:
    Image *img;
    if (GetOpenFileName(&ofn)==TRUE)
    {
    img->FromFile((LPCWSTR)&ofn.lpstrFile, FALSE);
    CLSID encClsid;
    GetEncoderClsid(L"image/tiff", &encClsid);
    img->Save(L"_myimage.tiff", (const CLSID*)&encClsid, 0);
    }
    опять какая-то глупость получается:
    Error 14 error LNK2001: unresolved external symbol _free Test.obj Test
    Error 15 error LNK2001: unresolved external symbol _malloc Test.obj Test
    Error 16 fatal error LNK1120: 2 unresolved externals C:\Documents and Settings\Siv Soft\Мои документы\Visual Studio 2008\Projects\Test\Release\Test.exe Test
     
  19. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    sivsoft
    Через классы - никаких проблем, да и в асме (где только flat) такого рода заморочек не припомню. В аттаче пример с сохранением через Save.
    Создать картинку как класс и сохранить через GdipSaveImageToFile у меня не получилось - не разобрался как передать такой объект flat функции, значит "смешанный" подход не проходит, да и смысла использовать flat api под С++ по прежнему не вижу.
     
  20. sivsoft

    sivsoft New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2008
    Сообщения:
    82
    Y_Mur
    огромное спасибо - все сохраняет, но остался еще один вопрос. Замучался с этими WCHAR LPWSTR LPCSTR и т.д. Честно говоря Микрософт намутил кучу маразма.
    Вообщем открываю файл в эту структуру:

    OPENFILENAME ofn;
    char szFile[255];

    ZMemProc ZMemAddr;
    ZMemAddr = (ZMemProc)GetProcAddress(LoadLibrary("kernel32.dll"), "RtlZeroMemory");
    (ZMemAddr)(&ofn, sizeof(OPENFILENAME));
    (ZMemAddr)(&szFile, sizeof(szFile));
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFile = szFile;
    ofn.nMaxFile = sizeof(szFile);
    ofn.lpstrFilter = "Графика JPEG\0*.jpg\0Графика BMP\0*.bmp\0";
    ofn.nFilterIndex = 1;
    ofn.lpstrFileTitle = NULL;
    ofn.nMaxFileTitle = 0;
    ofn.lpstrInitialDir = "C:";
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    if (GetOpenFileName(&ofn)==TRUE)
    {
    ...
    }
    получаю на выходе в ofn.lpstrFile - имя файла в виде указателя на строку.
    теперь мне нужно получить эту же строку, но в виде WCHAR *
    имя файла передать в виде:
    WCHAR *fnm;
    fnm = L"C:\\Downloads\\scan 1.jpg";
    получается отлично и работает и понимает, но если пробовать сделать что-то в виде:
    fnm = (WCHAR *)ofn.lpstrFile;
    в fnm получаем действительно строку C:\Downloads\scan 1.jpg
    но ее не понимает:
    Bitmap img(fnm, NULL);
    а L"C:\\Downloads\\scan 1.jpg"; - понимает.
    не пойму в чем проблема?