Как я могу сделать снимок экрана и сохранить его как JPEG в Windows?

предлагается использовать с фигурными скобками, я видел некоторые проблемы с оператором if else без фигурных скобок, (я точно не помню), т.е. с оператором if, который не был выполнен, когда я добавил то же самое с фигурными скобками, тогда работал только. (Использование Visual studio & C # 4.0).

13
задан Sinan Ünür 18 June 2009 в 14:17
поделиться

10 ответов

Хорошо, после огромных усилий вот ответ:

int SaveJpeg(HBITMAP hBmp, LPCWSTR lpszFilename, ULONG uQuality)
{
    ULONG *pBitmap = NULL;
    CLSID imageCLSID;
    EncoderParameters encoderParams;
    int iRes = 0;

    typedef Status (WINAPI *pGdipCreateBitmapFromHBITMAP)(HBITMAP, HPALETTE, ULONG**);
    pGdipCreateBitmapFromHBITMAP lGdipCreateBitmapFromHBITMAP;

    typedef Status (WINAPI *pGdipSaveImageToFile)(ULONG *, const WCHAR*, const CLSID*, const EncoderParameters*);
    pGdipSaveImageToFile lGdipSaveImageToFile;

    // load GdipCreateBitmapFromHBITMAP
    lGdipCreateBitmapFromHBITMAP = (pGdipCreateBitmapFromHBITMAP)GetProcAddress(hModuleThread, "GdipCreateBitmapFromHBITMAP");
    if(lGdipCreateBitmapFromHBITMAP == NULL)
    {
        // error
        return 0;
    }

    // load GdipSaveImageToFile
    lGdipSaveImageToFile = (pGdipSaveImageToFile)GetProcAddress(hModuleThread, "GdipSaveImageToFile");
    if(lGdipSaveImageToFile == NULL)
    {
        // error
        return 0;
    }

        lGdipCreateBitmapFromHBITMAP(hBmp, NULL, &pBitmap);

       iRes = GetEncoderClsid(L"image/jpeg", &imageCLSID);
       if(iRes == -1)
    {
        // error
        return 0;
    }
    encoderParams.Count = 1;
    encoderParams.Parameter[0].NumberOfValues = 1;
    encoderParams.Parameter[0].Guid  = EncoderQuality;
    encoderParams.Parameter[0].Type  = EncoderParameterValueTypeLong;
    encoderParams.Parameter[0].Value = &uQuality;

    lGdipSaveImageToFile(pBitmap, lpszFilename, &imageCLSID, &encoderParams);


    return 1;
}
  • что такое hModuleThread? Посмотрите здесь . Вы можете заменить на GetModuleHandle ()

  • , что такое GetEncoderClsid? Посмотрите здесь .

Теперь вопрос в том,

17
ответ дан 1 December 2019 в 21:25
поделиться

Good image compression is hard. There's a reason library code exists for the common formats. It requires a lot of code to do. Your constraints on the problem don't make it sound like there is a practical solution.

There are a couple things to try.

  1. Use an 8-bit per pixel BMP rather than a true color BMP. This assumes that the information loss in color mapping is acceptable, of course. It will buy you a factor of three in file size over a 24-bit BMP.

  2. Try using run length encoding in the BMP you write. RLE is a documented format for BMP, and there should be plenty of sample code out there to make it. It works best on images that have a lot of long runs of identical color. A typical screen without too many gradients and fills fits that description.

  3. If those aren't sufficient, then you might need to resort to a stronger compression. The source code to libjpeg is readily available, and it is possible to statically link it rather than using the DLL. It will require some effort to configure in only the bits you need, but the compression and decompression code are almost completely independent of each other and that splits the library almost in half.

0
ответ дан 1 December 2019 в 21:25
поделиться

Перевод на плоский GDI + API довольно прост:

void SaveJpeg(HBITMAP hBmp, LPCWSTR lpszFilename, ULONG uQuality)
{
    GpBitmap* pBitmap;
    GdipCreateBitmapFromHBITMAP(hBmp, NULL, &pBitmap);

    CLSID imageCLSID;
    GetEncoderClsid(L"image/jpeg", &imageCLSID);

    EncoderParameters encoderParams;
    encoderParams.Count = 1;
    encoderParams.Parameter[0].NumberOfValues = 1;
    encoderParams.Parameter[0].Guid  = EncoderQuality;
    encoderParams.Parameter[0].Type  = EncoderParameterValueTypeLong;
    encoderParams.Parameter[0].Value = &uQuality;

    GdipSaveImageToFile(pBitmap, lpszFilename, &imageCLSID, &encoderParams);
}

Единственное, что не было очевидным, - это очистка GpBitmap, созданная GdipCreateBitmapFromHBITMAP (). Класс Gdiplus :: Bitmap, похоже, не имеет деструктора, поэтому ничего не делает с его внутренним GpBitmap. Кроме того, нет GdipDeleteBitmap (), как и для других объектов GDI +. Поэтому мне непонятно, что нужно делать, чтобы избежать утечек.

Редактировать: Этот код не учитывает тот факт, что поставляемые Microsoft файлы заголовков GDI + объявляют все необходимые функции в пространствах имен C ++. Одно из решений - скопировать необходимые объявления (и при необходимости преобразовать их в код C) в свой собственный заголовок. Другая возможность - использовать заголовки, предоставленные проектами Wine или Mono . Оба они выглядят намного лучше для компиляции в виде кода C.

5
ответ дан 1 December 2019 в 21:25
поделиться

Вам, вероятно, придется использовать внешнюю библиотеку для создания JPEG в коде C - для этого не будет стандартной библиотечной функции. Конечно, вы также можете изучить формат файла и написать функцию для создания своей собственной на основе критериев. Вы можете начать в википедии . Если вы действительно не можете просто использовать внешнюю библиотеку, вы можете прочитать соответствующие функции библиотеки, чтобы узнать, как создавать свои собственные файлы JPEG. Но это звучит как намного больше работы, чем просто использование библиотеки.

Кроме того, я не верю, что размер библиотеки действительно влияет на C - я считаю, что вы получаете только размер функций, из которых вызываете эта библиотека (я думаю, по крайней мере). Конечно, если бы все функции были тесно связаны, это все равно было бы огромным.

0
ответ дан 1 December 2019 в 21:25
поделиться

Вы видели FreeImage Project ? Да, это внешняя библиотека, но она довольно маленькая (~ 1Мб). Делает все, что вы хотите, с изображениями тоже. Определенно стоит знать об этом, даже если не для этого проекта.

0
ответ дан 1 December 2019 в 21:25
поделиться

libjpeg - это бесплатная библиотека с открытым исходным кодом, написанная на C. Вы можете скопировать их код в свой.

http://sourceforge.net/project/showfiles.php?group_id=159521

0
ответ дан 1 December 2019 в 21:25
поделиться

Я знаю, что это не ответ на ваш вопрос, но я бы сказал, что вам не следует этого делать, даже если вы можете. Мне кажется, что такой подход упрощает случайную отправку конфиденциальной информации по обычной электронной почте. Пользователи могут легко случайно щелкнуть обычную кнопку отправки, потому что она находится рядом с кнопкой «отправить безопасную». Даже если вы разместите их на противоположных сторонах окна друг от друга, пользователь, скорее всего, по привычке нажмет обычную рассылку. Если вы не можете программно определить, что информация является конфиденциальной и ее необходимо безопасно отправлять, я думаю, что пользователей следует заставить использовать отдельное приложение, чтобы они всегда осознавали важность своего общения. Даже если бы вы могли автоматически обнаруживать конфиденциальную информацию (я бы не стал

-1
ответ дан 1 December 2019 в 21:25
поделиться

Одна возможность: если вы не можете изменить эту программу для сохранения в формате Jpeg, напишите вторую программу, используя C # / GDI + / другие причудливые технологии для мониторинга каталога сохранения и обработки сохраненных BMP в jpeg. .

Если вы не можете этого сделать, то независимая группа Jpeg сделала код Jpeg на чистом C доступным с конца 20 века: Здесь доступна минимальная веб-страница.

4
ответ дан 1 December 2019 в 21:25
поделиться

Если вас действительно беспокоит пространство, вы, вероятно, также можете отказаться от библиотек времени выполнения C. Если вы используете только несколько функций, просто напишите свою версию (например, strcpy). Можно писать приложения Windows размером всего несколько килобайт. Я могу отправить вам небольшой образец приложения, которое делает это.

Если я возьму свой код визуализации C и разделю его до кодировщика JPEG, он, вероятно, создаст около 20 КБ кода (меньше, если вам не нужно поддерживать изображения в градациях серого).

0
ответ дан 1 December 2019 в 21:25
поделиться

Try this at the begining of your code

#include "windows.h"
#include "gdiplus.h"
using namespace Gdiplus;
using namespace Gdiplus::DllExports;

And GdipSaveImageToFile() may compile, in c++ i believe.

In pure C, probably the best is to try to make single includes. Look for the functions declarations in "gdiplus.h" and add minimal includes for each of the functions that do not include namespaces, such as #include "Gdiplusflat.h" for the GdipSaveImageToFile()

1
ответ дан 1 December 2019 в 21:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: