locked
Save char array as JPG

    Question

  • Given the following

    • Bitmap raw image data in char array
    • Image width and height
    • Path wzAppDataDirectory in std::wstring generated using
    	// Get a good path.
    	wchar_t wzAppDataDirectory[MAX_PATH];
    	wcscpy_s( wzAppDataDirectory, MAX_PATH, Windows::Storage::ApplicationData::Current->LocalFolder->Path->Data() );
    	wcscat_s( wzAppDataDirectory, MAX_PATH, (std::wstring(L"\\") + fileName).c_str() );

    How can we save the image as JPG? (Include encoding as well as the char array is raw bitmap form)

    Code example is very much appreciated.


    Wednesday, November 14, 2012 3:46 PM

Answers

  • This is an example code which I obtained from my friend. It uses OpenCV's Mat data structure. Note that, you need to ensure the unsigned char data array within cv::Mat is in continuous form. cv::cvtColor will do the trick (Or, cv::Mat.clone)

    Take note, do not use OpenCV's imwrite. As at current time of writing, imwrite doesn't pass Windows Store Certification Test. It is using several APIs, which is prohibited in WinRT.

    void SaveMatAsJPG(const cv::Mat& mat, const std::wstring fileName)
    {
        cv::Mat tempMat;
        cv::cvtColor(mat, tempMat, CV_BGR2BGRA);
    
        Platform::String^ pathName = ref new Platform::String(fileName.c_str());
       
        task<StorageFile^>(ApplicationData::Current->LocalFolder->CreateFileAsync(pathName, CreationCollisionOption::ReplaceExisting)).
        then([=](StorageFile^ file)
        {
            return file->OpenAsync(FileAccessMode::ReadWrite);
        }).
        then([=](IRandomAccessStream^ stream)
        {
            return BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId, stream);
        }).
        then([=](BitmapEncoder^ encoder)
        {
            const Platform::Array<unsigned char>^ pixels = ref new Platform::Array<unsigned char>(tempMat.data, tempMat.total() * tempMat.channels());
            encoder->SetPixelData(BitmapPixelFormat::Bgra8, BitmapAlphaMode::Ignore, tempMat.cols , tempMat.rows, 96.0, 96.0, pixels);
            encoder->FlushAsync();
        });
    }


    Friday, November 16, 2012 9:12 AM

All replies

  • Take a look at http://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmapencoder.aspx, in particular the methods:

    CreateAsync(Guid, IRandomAccessStream )

    SetPixelData

    FlushAsync

    There is also a way to control the quality of the created JPG:

    using namespace Windows::Graphics::Imaging;
    BitmapPropertySet ^ bitmapPropertiesSet= ref new BitmapPropertySet();
    bitmapPropertiesSet->Insert( "ImageQuality", ref new BitmapTypedValue( quality, PropertyType::Single ) );
    // See http://msdn.microsoft.com/en-us/library/windows/desktop/gg430026(v=vs.85).aspx      Native WIC Codecs
    
    task< BitmapEncoder^ > getEncoderTask( BitmapEncoder::CreateAsync( BitmapEncoder::JpegEncoderId, putJpgStream, bitmapPropertiesSet ) ); 
    
    etc
    

    • Proposed as answer by Jesse Jiang Friday, November 16, 2012 6:26 AM
    • Edited by Andrew7Webb Friday, November 16, 2012 4:33 PM add quality
    Wednesday, November 14, 2012 5:00 PM
  • This is an example code which I obtained from my friend. It uses OpenCV's Mat data structure. Note that, you need to ensure the unsigned char data array within cv::Mat is in continuous form. cv::cvtColor will do the trick (Or, cv::Mat.clone)

    Take note, do not use OpenCV's imwrite. As at current time of writing, imwrite doesn't pass Windows Store Certification Test. It is using several APIs, which is prohibited in WinRT.

    void SaveMatAsJPG(const cv::Mat& mat, const std::wstring fileName)
    {
        cv::Mat tempMat;
        cv::cvtColor(mat, tempMat, CV_BGR2BGRA);
    
        Platform::String^ pathName = ref new Platform::String(fileName.c_str());
       
        task<StorageFile^>(ApplicationData::Current->LocalFolder->CreateFileAsync(pathName, CreationCollisionOption::ReplaceExisting)).
        then([=](StorageFile^ file)
        {
            return file->OpenAsync(FileAccessMode::ReadWrite);
        }).
        then([=](IRandomAccessStream^ stream)
        {
            return BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId, stream);
        }).
        then([=](BitmapEncoder^ encoder)
        {
            const Platform::Array<unsigned char>^ pixels = ref new Platform::Array<unsigned char>(tempMat.data, tempMat.total() * tempMat.channels());
            encoder->SetPixelData(BitmapPixelFormat::Bgra8, BitmapAlphaMode::Ignore, tempMat.cols , tempMat.rows, 96.0, 96.0, pixels);
            encoder->FlushAsync();
        });
    }


    Friday, November 16, 2012 9:12 AM