Доброго времени суток! Программа на С++ под чистое WINAPI. CRT убран. Как можно с помощью GDI+ загрузить картинку и сохранить ее. Как инициализировать понятно: GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); Непонятно как потом действовать. И еще как WCHAR *, который часто используется преобразовывать в char, LPSTR и обратно?
sivsoft Собственно ничего сложного - берёшь любой "классовый" пример, которых в msdn много и по таблицам преобразуешь в flat версию, но это конечно извращение оправданное в асме ), а в С++ чтобы GDI+ работало без CRT достаточно определить свои new/delete, и пару "заглушек" на некоторые заморочки, например так: Код (Text): // Глобальные переменные проекта extern LPVOID activeHeap; // активная куча памяти // Упрощённые полезные части CRT void * __cdecl operator new(size_t n) { return (HANDLE *)HeapAlloc(activeHeap, 0, n); } void __cdecl operator delete(void * p) { if (p!=NULL) HeapFree(activeHeap, 0, p); } // Заглушки чтобы компилятор не ругался // Константы: extern "C" const int _fltused = 0x9876; extern "C" const int _ldused = 0x9876; // Класс-заглушка RTTI сильно урезан: class type_info { public: virtual __thiscall ~type_info() {} private: __thiscall type_info(_In_ const type_info& _Rhs); }; type_info::type_info(const type_info& rhs){}; Это можно кинуть в любой модуль проекта или прицепить отдельным. В начале программы есно сделать: activeHeap = GetProcessHeap(); И всё будет чудесно работать без заморочек с Flat.
Преобразовывать в/из unicode можно MultiByteToWideChar/WideCharToMultiByte или wsprintf(A/W) с ключём %S но может стоит подумать о полном переводе проекта на уникод?
sivsoft Преобразовывать ASCII->unicode, особенно если латиница не то, что просто, а очень просто Код (Text): mov ah,0 a1: lodsb stosw test al,al loopne a1
Y_Mur Error 15 error LNK2001: unresolved external symbol "void * activeHeap" (?activeHeap@@3PAXA) Test.obj Test Mikl___ спасибо опробую
sivsoft extern LPVOID activeHeap; нужно включать во все файлы где используется new/delete, остальное достаточно один раз, можно даже прицепить к проекту отдельным файлом, котрый никуда не включается - линкер разберётся. А в unicode кроме латиницы, есть и кириллица и спецсимволы, преобразовывать которые самому тоже можно, но имхо без особой нужды не стоит.
Ещё одна "фишка" GDI+ - падение программы при попытках использования неудачно сконструированных шрифтов, перьев, и т.п., что наиболее неприятно в текстовых функциях, ведь шрифты могут на другом компьютере просто отсутствовать, так что не забывай проверять в программе успешность создания шрифта перед его использованием.
Да ещё в том примере маленький глючёк - экранный контекст тоже нужно освобождать - в этом простейшем примере это конечно произойдёт автоматически при завершении, но в общем случае конструкция Graphics graph(GetDC(0)); не удачная и её нужно заменить на: HDC hDC = GetDC(0); Graphics graph(hDC); ... ReleaseDC(0, hDC);
Y_Mur класс только вот не могу понять за сохранение - неужели нет функции не сохраняющей в потоке?? я, например, пробую так загрузить файл: Image *img; if (GetOpenFileName(&ofn)==TRUE) { img->FromFile((LPCWSTR)&ofn.lpstrFile, FALSE); } а вот сохранить - там тольков stream. Или не так что делаю?
У 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
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
Flat функции "спрятаны" в namespace Gdiplus:llExports если используешь только flat замени #include <gdiPlus.h> на #include "GdiplusFlat.h" или если "смешиваешь" то уточняй namespase
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 а если вместе использовать, то тоже самое ругается что не найдет идентификатор.
Пробую так: 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
sivsoft Через классы - никаких проблем, да и в асме (где только flat) такого рода заморочек не припомню. В аттаче пример с сохранением через Save. Создать картинку как класс и сохранить через GdipSaveImageToFile у меня не получилось - не разобрался как передать такой объект flat функции, значит "смешанный" подход не проходит, да и смысла использовать flat api под С++ по прежнему не вижу.
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"; - понимает. не пойму в чем проблема?