How to load file font into RAM using C/C++ and SDL2? - c++

Accordingly to the ''best practices'' I have learned, we should load the resources we need to our programs into RAM, avoiding unnecessary requests to user's hard drive. Using SDL2, I always free image files after loading them into RAM. (File -> Surface -> Texture -> Free File/Surface). So, if I other application changes the file, my program ignores it, as the file is not in use by it anymore.
Now in lesson 16 I am learning to use the Add-on SDL_ttf.
However, using SDL_ttf addon I could not find a way to free the font.ttf file, loading it into RAM too. I can only see it through a pointer. It seems to me that the file keeps being read each time I render a text.
How can I load it into RAM, so the rendering calls a RAM position, instead of the file in HD?
Full code
#define SDL_MAIN_HANDLED
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
int G = 255;
int main (void) {SDL_SetMainReady();
int SCREEN_WIDTH = 800;
int SCREEN_HEIGHT = 600;
bool QUIT_APPLICATION = false;
SDL_Event union_Event_manager;
SDL_Color str_White_colour = {255,255,255,255};
SDL_Window * ptr_Window = nullptr;
SDL_Surface * ptr_Text_Surface = nullptr;
SDL_Surface * ptr_Main_surface = nullptr;
SDL_RWops * ptr_str_rwops = nullptr;
TTF_Font * ptr_Font = nullptr;
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
ptr_Window = SDL_CreateWindow("Lesson 16 - TrueTypeFonts", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
ptr_Main_surface = SDL_GetWindowSurface(ptr_Window);
ptr_str_rwops = SDL_RWFromFile("FreeMono.ttf", "r");
ptr_Font = TTF_OpenFontIndexRW(ptr_str_rwops, 1, 72, 0);
ptr_Text_Surface = TTF_RenderText_Solid(ptr_Font, "Hello World", str_White_colour);
while(!QUIT_APPLICATION){
while(SDL_PollEvent(&union_Event_manager) != 0 ){
if (union_Event_manager.type == SDL_QUIT) {QUIT_APPLICATION = true;}
/*END WHILE*/}
SDL_BlitSurface(ptr_Text_Surface, NULL, ptr_Main_surface, NULL);
SDL_UpdateWindowSurface(ptr_Window);
/*END WHILE*/}
TTF_CloseFont(ptr_Font);
// if called before any rendering, the app crashes, as supposed to.
// So, how free the **file** and keep using its content from RAM?
SDL_RWclose(ptr_str_rwops);
SDL_FreeSurface(ptr_Text_Surface);
SDL_FreeSurface(ptr_Main_surface);
SDL_DestroyWindow(ptr_Window);
ptr_Font = nullptr;
ptr_str_rwops = nullptr;
ptr_Text_Surface = nullptr;
ptr_Main_surface = nullptr;
ptr_Window = nullptr;
TTF_Quit();
SDL_Quit();
return (0);}
Failure 1:
Create a structure to hold information from file.
TTF_Font str_Font; // Error in compilation ''incomplete type''
str_Font = *ptr_Font;
TTF_CloseFont(ptr_Font);
ptr_Font = nullptr;
ptr_Font = &str_Font;
Reason to failure:
I misunderstood how the file works. The structure only holds information about the file, not the media itself.
This approach is useless, and crash the program just after freeing the pointer (the rendering tries to dereference a nullptr).
Failure 2:
Use built in function to free resource.
ptr_Font = TTF_OpenFontIndexRW(SDL_RWFromFile("FreeMono.ttf", "r"), 1, 72, 0);
Reason to failure:
I do not understand why, as the second argument (non-zero) specifies it should free the resource after usage. It also happens in the completed source code above, where I merely separated the functions in two lines.
Failure 3:
Create structure to hold information about pointer.
ptr_str_rwops = SDL_RWFromFile("FreeMono.ttf", "r");
str_rwops = *ptr_str_rwops;
SDL_RWclose(ptr_str_rwops); // crashes the program
ptr_str_rwops = nullptr;
ptr_str_rwops = &str_rwops; // useless: file still in use.
Reason to failure:
The structure RWops seems to not hold the file, only information about it. So it is the sum of failure 1 and 2.
Failure 4:
Tried to load file as object.
ptr_LoadObject = (TTF_Font*)SDL_LoadObject("FreeMono.ttf");
ptr_str_rwops = SDL_RWFromFile((const char *)ptr_LoadObject, "r");
Reason to failure:
This function works with shared operational system files. Wrong usage of function.
Update 2019-04-05
Failure 5
Tried to make a copy of file directly into RAM useing memcpy
long int func_discover_file_size(char* file){
long int var_file_size = 0;
FILE * ptr_file = nullptr;
ptr_file = fopen(file, "rb");
fseek(ptr_file , 0L , SEEK_END);
var_file_size = ftell(ptr_file);
fclose(ptr_file);
return var_file_size;
/*END func_discover_file_size*/}
int main (void) {
/*cut unrelated code*/
void * ptr_load_file = nullptr;
void * ptr_File_copy = nullptr;
long int var_file_size = 0;
/*cut unrelated code*/
var_file_size = func_discover_file_size("FreeMono.ttf");
// works fine and returns correct size of file.
ptr_File_copy = (char*) calloc (1, var_file_size);
// memory allocation works fine (tested)
ptr_load_file = fopen("FreeMono.ttf", "rb");
// file loaded correctly. Test with FOR LOOP shows content of file in console.
memcpy(ptr_File_copy, ptr_load_file, var_file_size);
// program crashes in line above
Reason to failure:
It looks like I do not know how to correctly use memcpy. I tried many many casts to function and pointers (void, char), tried to change type of pointers to char, void, FILE, tried to output to a third pointer...
Now I am looking for a good soul to enlight my ways... :-p
note: C tagged because SDL

While freetype (which SDL_ttf uses) will not read font more than once (which it can't, since its API doesn't provide seek functionality), SDL_ttf will not close file/RWops until font closes. You can achieve what you've described via manually loading file into memory buffer and using that memory as RWops to feed data to SDL_ttf, e.g. (no error checking, no free, etc. - this is just an example):
/* 'slurp' file (read entire file into memory buffer)
* there are multiple ways to do so
*/
SDL_RWops *file_rw = SDL_RWFromFile("font.ttf", "rb");
Sint64 file_sz = file_rw->size(file_rw);
void *membuf = malloc(file_sz);
file_rw->read(file_rw, membuf, 1, file_sz);
file_rw->close(file_rw);
/* use memory buffer as RWops */
SDL_RWops *mem_rw = SDL_RWFromConstMem(membuf, file_sz);
TTF_Font *font = TTF_OpenFontRW(mem_rw, 1, font_size);
/* free(membuf) when you're done with the font */

The secondary question about memcpy can be solved in the following way:
memcpy copies a file object, not its contents. In order to read from it:
Use fread function to read from FILE*: fread(ptr_File_copy, 1,
var_file_size, ptr_load_file) instead of memcpy.

Related

Processing audio file in memory with lib sox

I am trying to process audio file in memory with SOX C++ API and I stuck at the very beginning. The goal is to load an audio file from disk, apply few effects (tempo/gain adjustments) in memory. Here is the code I started with, but I receive a strange error when creating out stream:
formats: can't open output file `': No such file or directory
What could be an issue here? I am testing it on Mac. Here is the code:
#include <iostream>
#include <sox.h>
#include <assert.h>
int main() {
sox_format_t * in, *out;
sox_effect_t * e;
sox_init();
in = sox_open_read("/path/to/file.wav", NULL, NULL, NULL);
sox_format_t *out_format = (sox_format_t *)malloc(sizeof(sox_format_t));
memcpy(out_format, in, sizeof(sox_format_t));
char * buffer;
size_t buffer_size;
out = sox_open_memstream_write(&buffer, &buffer_size, &in->signal, NULL, "sox", NULL);
//chain = sox_create_effects_chain(&in->encoding, &out->encoding);
//e = sox_create_effect(sox_find_effect("input"));
return 0;
}
sox_open_memstream_write() uses either fmemopen() or open_memstream() depending on the parameters you pass.
Some (or all) versions of OSX do not have these functions.
The same is true for Windows.
You can find the relevant code in file src/formats.c, function open_write(), look for the #ifdef HAVE_FMEMOPEN conditionals.

Simple node C addon for memory mapped file crashes node

My goal is to create a simple addon that opens a memory mapped file and gives node raw access to the buffer. The memory mapped file already exists so I don't need to create a new file -- error will be thrown if file not already created (by another process).
Here is what I have so far:
#include <nan.h>
#include <windows.h>
using namespace v8;
void get_shm(const Nan::FunctionCallbackInfo <v8::Value> &info) {
if (info.Length() != 1) {
return Nan::ThrowTypeError("Wrong number of arguments. You must specify size of mapped file!");
}
if (!info[0]->IsNumber()) {
return Nan::ThrowTypeError("Bad argument. Size of mapped file must be a number!");
}
int len = info[0]->Uint32Value();
HANDLE h = OpenFileMappingA(FILE_MAP_WRITE | FILE_MAP_READ, 1, "Global\\_GB_SharedMemory_Read");
if (h == NULL) {
Nan::ThrowTypeError("Couldn't open memory mapped file");
}
char *buf = (char *) MapViewOfFile(h, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, len);
Nan::MaybeLocal<Object> jsbuf = Nan::NewBuffer(buf, len);
info.GetReturnValue().Set(jsbuf.ToLocalChecked());
}
void Init(v8::Local <v8::Object> exports) {
exports->Set(Nan::New("get_shm").ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(get_shm)->GetFunction());
}
NODE_MODULE(addon_shm, Init)
Unfortunately node is crashing (presumably due to access violation) at some point after the NewBuffer is returned. It doesn't crash immediately but some unpredictable time after.
I'm not attempting to read/write from the buffer in Javascript. The only line using the add on is this:
const buf=shm.get_shm(10);
Mapped file created by the other process is bigger than 10.
If I use malloc to create the buffer, problem doesn't occur.
If I just call get_shm(10) without storing the result, problem doesn't occur.
Struggling to understand the issue...

SDL2 & SMPEG2 - Empty sound buffer trying to read a MP3

I'm trying to load a MP3 in a buffer using the SMPEG2 library, which comes with the SDL2. Every SMPEG function calls returns without error, but when I'm done, the sound buffer is full of zeros.
Here's the code :
bool LoadMP3(char* filename)
{
bool success = false;
const Uint32 Mp3ChunkLen = 4096;
SMPEG* mp3;
SMPEG_Info infoMP3;
Uint8 * ChunkBuffer;
Uint32 MP3Length = 0;
// Allocate a chunk buffer
ChunkBuffer = (Uint8*)malloc(Mp3ChunkLen);
SDL_RWops *mp3File = SDL_RWFromFile(filename, "rb");
if (mp3File != NULL)
{
mp3 = SMPEG_new_rwops(mp3File, &infoMP3, 1, 0);
if(mp3 != NULL)
{
if(infoMP3.has_audio)
{
Uint32 readLen;
// Inform the MP3 of the output audio specifications
SMPEG_actualSpec(mp3, &asDeviceSpecs); // static SDL_AudioSpec asDeviceSpecs; containing valid values after a call to SDL_OpenAudioDevice
// Enable the audio and disable the video.
SMPEG_enableaudio(mp3, 1);
SMPEG_enablevideo(mp3, 0);
// Play the MP3 once to get the size of the needed finale buffer
SMPEG_play(mp3);
while ((readLen = SMPEG_playAudio(mp3, ChunkBuffer, Mp3ChunkLen)) > 0)
{
MP3Length += readLen;
}
SMPEG_stop(mp3);
if(MP3Length > 0)
{
// Reallocate the buffer with the new length (if needed)
if (MP3Length != Mp3ChunkLen)
{
ChunkBuffer = (Uint8*)realloc(ChunkBuffer, MP3Length);
}
// Replay the entire MP3 into the new ChunkBuffer.
SMPEG_rewind(mp3);
SMPEG_play(mp3);
bool readBackSuccess = (MP3Length == SMPEG_playAudio(mp3, ChunkBuffer, MP3Length));
SMPEG_stop(mp3);
if(readBackSuccess)
{
// !!! Here, ChunkBuffer contains only zeros !!!
success = true;
}
}
}
SMPEG_delete(mp3);
mp3 = NULL;
}
SDL_RWclose(mp3File);
mp3File = NULL;
}
free(ChunkBuffer);
return success;
}
The code's widely based on SDL_Mixer, which I cannot use for my projet, based on its limitations.
I know Ogg Vorbis would be a better choice of file format, but I'm porting a very old project, and it worked entirely with MP3s.
I'm sure the sound system is initialized correctly because I can play WAV files just fine. It's intialized with a frequency of 44100, 2 channels, 1024 samples, and the AUDIO_S16SYS format (the latter which is, as I understood from the SMPEG source, mandatory).
I've calculated the anticipated buffer size, based on the bitrate, the amount of data in the MP3 and the OpenAudioDevice audio specs, and everything is consistent.
I cannot figure why everything but the buffer data seems to be working.
UPDATE #1
Still trying to figure out what's wrong, I thought the support for MP3 might not be working, so I created the following function :
SMPEG *mpeg;
SMPEG_Info info;
mpeg = SMPEG_new(filename,&info, 1);
SMPEG_play(mpeg);
do { SDL_Delay(50); } while(SMPEG_status(mpeg) == SMPEG_PLAYING);
SMPEG_delete(mpeg);
The MP3 played. So, the decoding should actually be working. But that's not what I need ; I really need the sound buffer data so I can send it to my mixer.
After much tinkering, research and digging through the SMPEG source code, I realized that I had to pass 1 as the SDLAudio parameter to SMPEG_new_rwops function.
The comment found in smpeg.h is misleading :
The sdl_audio parameter indicates if SMPEG should initialize the SDL audio subsystem. If not, you will have to use the SMPEG_playaudio() function below to extract the decoded data.
Since the audio subsystem was already initialized and I was using the SMPEG_playaudio() function, I had no reason to think I needed this parameter to be non-zero. In SMPEG, this parameter triggers the audio decompression at opening time, but even though I called SMPEG_enableaudio(mp3, 1); the data is never reparsed. This might be a bug/a shady feature.
I had another problem with the freesrc parameter which needed to be 0, since I freed the SDL_RWops object myself.
For future reference, once ChunkBuffer has the MP3 data, it needs to pass through SDL_BuildAudioCVT/SDL_ConvertAudio if it's to be played through an already opened audio device.
The final working code is :
// bool ReadMP3ToBuffer(char* filename)
bool success = false;
const Uint32 Mp3ChunkLen = 4096;
SDL_AudioSpec mp3Specs;
SMPEG* mp3;
SMPEG_Info infoMP3;
Uint8 * ChunkBuffer;
Uint32 MP3Length = 0;
// Allocate a chunk buffer
ChunkBuffer = (Uint8*)malloc(Mp3ChunkLen);
memset(ChunkBuffer, 0, Mp3ChunkLen);
SDL_RWops *mp3File = SDL_RWFromFile(filename, "rb"); // filename is a char* passed to the function.
if (mp3File != NULL)
{
mp3 = SMPEG_new_rwops(mp3File, &infoMP3, 0, 1);
if(mp3 != NULL)
{
if(infoMP3.has_audio)
{
Uint32 readLen;
// Get the MP3 audio specs for later conversion
SMPEG_wantedSpec(mp3, &mp3Specs);
SMPEG_enablevideo(mp3, 0);
// Play the MP3 once to get the size of the needed buffer in relation with the audio specs
SMPEG_play(mp3);
while ((readLen = SMPEG_playAudio(mp3, ChunkBuffer, Mp3ChunkLen)) > 0)
{
MP3Length += readLen;
}
SMPEG_stop(mp3);
if(MP3Length > 0)
{
// Reallocate the buffer with the new length (if needed)
if (MP3Length != Mp3ChunkLen)
{
ChunkBuffer = (Uint8*)realloc(ChunkBuffer, MP3Length);
memset(ChunkBuffer, 0, MP3Length);
}
// Replay the entire MP3 into the new ChunkBuffer.
SMPEG_rewind(mp3);
SMPEG_play(mp3);
bool readBackSuccess = (MP3Length == SMPEG_playAudio(mp3, ChunkBuffer, MP3Length));
SMPEG_stop(mp3);
if(readBackSuccess)
{
SDL_AudioCVT convertedSound;
// NOTE : static SDL_AudioSpec asDeviceSpecs; containing valid values after a call to SDL_OpenAudioDevice
if(SDL_BuildAudioCVT(&convertedSound, mp3Specs.format, mp3Specs.channels, mp3Specs.freq, asDeviceSpecs.format, asDeviceSpecs.channels, asDeviceSpecs.freq) >= 0)
{
Uint32 newBufferLen = MP3Length*convertedSound.len_mult;
// Make sure the audio length is a multiple of a sample size to avoid sound clicking
int sampleSize = ((asDeviceSpecs.format & 0xFF)/8)*asDeviceSpecs.channels;
newBufferLen &= ~(sampleSize-1);
// Allocate the new buffer and proceed with the actual conversion.
convertedSound.buf = (Uint8*)malloc(newBufferLen);
memcpy(convertedSound.buf, ChunkBuffer, MP3Length);
convertedSound.len = MP3Length;
if(SDL_ConvertAudio(&convertedSound) == 0)
{
// Save convertedSound.buf and convertedSound.len_cvt for future use in your mixer code.
// Dont forget to free convertedSound.buf once it's not used anymore.
success = true;
}
}
}
}
}
SMPEG_delete(mp3);
mp3 = NULL;
}
SDL_RWclose(mp3File);
mp3File = NULL;
}
free(ChunkBuffer);
return success;
NOTE : Some MP3 files I tried lost a few milliseconds and cutoff too early during playback when I resampled them with this code. Some others didn't. I could reproduce the same behaviour in Audacity, so I'm not sure what's going on. There may still have a bug with my code, a bug in SMPEG, or it maybe a known issue with the MP3 format itself. If someone can provide and explanation in the comments, that would be great!

Suppress system() output

First off, I do mostly C#, .Net development so go easy on me if this is a stupid question.
I am implementing an Ericcson open source project to convert an image to another format. The problem is that on conversion an output to a console happens as follows...
1 file(s) copied.
I need to suppress this dialog that pops up. I just want to execute the system command with no output. I think I have isolated the area of the code causing this.
void writeOutputFile(char *dstfile, uint8* img, uint8* alphaimg, int width, int height)
{
char str[300];
if(format!=ETC2PACKAGE_R_NO_MIPMAPS&&format!=ETC2PACKAGE_RG_NO_MIPMAPS)
{
fWritePPM("tmp.ppm",width,height,img,8,false);
//PRINTF("Saved file tmp.ppm \n\n");
}
else if(format==ETC2PACKAGE_RG_NO_MIPMAPS)
{
fWritePPM("tmp.ppm",width,height,img,16,false);
}
if(format==ETC2PACKAGE_RGBA_NO_MIPMAPS||format==ETC2PACKAGE_RGBA1_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA1_NO_MIPMAPS)
fWritePGM("alphaout.pgm",width,height,alphaimg,false,8);
if(format==ETC2PACKAGE_R_NO_MIPMAPS)
fWritePGM("alphaout.pgm",width,height,alphaimg,false,16);
// Delete destination file if it exists
if(fileExist(dstfile))
{
sprintf(str, "del %s\n",dstfile);
system(str);
}
int q = find_pos_of_extension(dstfile);
if(!strcmp(&dstfile[q],".ppm")&&format!=ETC2PACKAGE_R_NO_MIPMAPS)
{
// Already a .ppm file. Just rename.
sprintf(str,"move tmp.ppm %s\n",dstfile);
//PRINTF("Renaming destination file to %s\n",dstfile);
}
else
{
// Converting from .ppm to other file format
//
// Use your favorite command line image converter program,
// for instance Image Magick. Just make sure the syntax can
// be written as below:
//
// C:\imconv source.ppm dest.jpg
//
if(format==ETC2PACKAGE_RGBA_NO_MIPMAPS||format==ETC2PACKAGE_RGBA1_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA1_NO_MIPMAPS)
{
// Somewhere after version 6.7.1-2 of ImageMagick the following command gives the wrong result due to a bug.
// sprintf(str,"composite -compose CopyOpacity alphaout.pgm tmp.ppm %s\n",dstfile);
// Instead we read the file and write a tga.
//PRINTF("Converting destination file from .ppm/.pgm to %s with alpha\n",dstfile);
int rw, rh;
unsigned char *pixelsRGB;
unsigned char *pixelsA;
fReadPPM("tmp.ppm", rw, rh, pixelsRGB, 8);
fReadPGM("alphaout.pgm", rw, rh, pixelsA, 8);
fWriteTGAfromRGBandA(dstfile, rw, rh, pixelsRGB, pixelsA, true);
free(pixelsRGB);
free(pixelsA);
sprintf(str,""); // Nothing to execute.
}
else if(format==ETC2PACKAGE_R_NO_MIPMAPS)
{
sprintf(str,"imconv alphaout.pgm %s\n",dstfile);
//PRINTF("Converting destination file from .pgm to %s\n",dstfile);
}
else
{
sprintf(str,"imconv tmp.ppm %s\n",dstfile);
//PRINTF("Converting destination file from .ppm to %s\n",dstfile);
}
}
// Execute system call
system(str);
free(img);
if(alphaimg!=NULL)
free(alphaimg);
}
I am lost at this point about how to suppress the console that pops up. As we iterate through images via a reference to the dll, many many console windows flash on the screen. Need to stop this from happening.
Help is greatly appreciated.
Try doing:
strcat( str, " > nul" ) // for Windows or
//strcat( str, " > /dev/null" ) // for Unix
system( str )
If it doesn't help then this may help:
#include <string>
#include <ShellAPI.h>
int system_no_output( std::string command )
{
command.insert( 0, "/C " );
SHELLEXECUTEINFOA ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = "cmd.exe";
ShExecInfo.lpParameters = command.c_str();
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_HIDE;
ShExecInfo.hInstApp = NULL;
if( ShellExecuteExA( &ShExecInfo ) == FALSE )
return -1;
WaitForSingleObject( ShExecInfo.hProcess, INFINITE );
DWORD rv;
GetExitCodeProcess( ShExecInfo.hProcess, &rv );
CloseHandle( ShExecInfo.hProcess );
return rv;
}
and replace all your system() calls to system_no_output() ones.
To fully suppress the output, redirect both stdout and stderr:
system("command >nul 2>nul");
Take a look here if you're using C#. The class used in C# is ProcessStartInfo.
In the example in the link, look at the OpenWithStartInfo member function which will minimize the console.
As far as doing this in C++, take a look at the spawn family of functions here.

C++ GDI+ loading an image from a file then deleting the file *before* unloading the image

Simply what it says on the tin
I'm loading a bitmap from a file using Bitmap::FromFile but afterwards I want to delete it from the disk.
The problem is, Bitmap::FromFile absolutely locks the file from any changes/deletion until the loaded image is unloaded
This is because I'm storing the bitmaps in a binary file, so I want to do it in this order:
1. extract the image from binary file
2. load the image
3. delete the file extracted in #1
(just some basic protection for my image resources, I just don't want them sitting in my program directory)
Bitmap::FromFile still locks the file from deletion even when cloning the loaded image from the file like in my attempt:
Bitmap* tempbmp = Bitmap::FromFile(fileanddir.c_str(),false);
Rect temprect( 0, 0, tempbmp->GetWidth(), tempbmp->GetHeight() );
// make the image to be used as a clone to the temporary
// bitmap to avoid file locking
image_to_be_used = tempbmp->Clone(temprect, PixelFormatDontCare);
// delete temporary loaded bitmap since it shouldn't be needed
delete tempbmp;
// delete the file itself, too bad the file is locked
int theresult = remove(tocharptr(fileanddir));
// returns -1, also: manually deleting at this point gives the error
// that the file is being used by another person/program
Any idea how I can load a bitmap or somehow copy it to memory so the file itself wouldn't be locked ?
(So i can delete it a moment after loading it)
You can do it this way
Gdiplus::Bitmap* LoadImageFromFileWithoutLocking(const WCHAR* fileName) {
using namespace Gdiplus;
Bitmap src( fileName );
if ( src.GetLastStatus() != Ok ) {
return 0;
}
Bitmap *dst = new Bitmap(src.GetWidth(), src.GetHeight(), PixelFormat32bppARGB);
BitmapData srcData;
BitmapData dstData;
Rect rc(0, 0, src.GetWidth(), src.GetHeight());
if (src.LockBits(& rc, ImageLockModeRead, PixelFormat32bppARGB, & srcData) == Ok)
{
if ( dst->LockBits(& rc, ImageLockModeWrite, PixelFormat32bppARGB, & dstData) == Ok ) {
uint8_t * srcBits = (uint8_t *) srcData.Scan0;
uint8_t * dstBits = (uint8_t *) dstData.Scan0;
unsigned int stride;
if (srcData.Stride > 0) {
stride = srcData.Stride;
} else {
stride = - srcData.Stride;
}
memcpy(dstBits, srcBits, src.GetHeight() * stride);
dst->UnlockBits(&dstData);
}
src.UnlockBits(&srcData);
}
return dst;
}
Take a look at Bitmap::FromStream. You should be able to use SHCreateStreamOnFileEx to open an IStream on the file. After loading your bitmap you can safely delete the stream and then the temporary file.
If the binary file is only compressed with a supported algorithm, then pass the corresponding flag to SHCreateStreamOnFileEx and have it read the archive, bypassing the extraction of the image into a temp file. Otherwise can implement the IStream interface to read the binary file and extract your image data directly.
if you interested in MFC-OLE sample:
CFile file;
CFileException fe;
CString strFileName = "C:\\yours.bmp";
if (!file.Open(strFileName, CFile::modeRead | CFile::shareDenyNone , &fe))
{
return;
}
COleStreamFile stream;
if(!stream.CreateMemoryStream(NULL))
{
return;
}
BYTE buf[1024];
int readed = 0;
do
{
readed = file.Read(buf,1024);
stream.Write(buf,readed);
}
while(readed > 0);
file.Close();
stream.SeekToBegin();
USES_CONVERSION;
m_pImage = new Gdiplus::Bitmap(stream.GetStream( ));