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

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( ));

Related

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

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.

Converting string to IMAGE_T

i'm working on a simple graphic application working with raspberry dispmanx.
My goal is to acquire a png file via stdin (from a RGBA array, formatted as a string, from a python app), convert it into the IMAGE_T format expected by dispmanx in order to display it.
Now, I only have a function that can acquire PNG from file, but it takes too much time to write the image on disk, event on tmpfs.
How can I rewrite this function to work with a string as input ?
I would have manage this alone, but i don't know how to emulate a file from a variable to feed png_ptr and info_ptr ...
#include <png.h>
#include <stdlib.h>
#include "bcm_host.h"
#include "loadpng.h"
//-------------------------------------------------------------------------
#ifndef ALIGN_TO_16
#define ALIGN_TO_16(x) ((x + 15) & ~15)
#endif
//-------------------------------------------------------------------------
bool
loadPngData(
IMAGE_T* image,
const char *file)
{
FILE* fpin = fopen(file, "rb");
if (fpin == NULL)
{
fprintf(stderr, "loadpng: can't open file for reading\n");
return false;
}
//---------------------------------------------------------------------
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL,
NULL,
NULL);
if (png_ptr == NULL)
{
fclose(fpin);
return false;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{
png_destroy_read_struct(&png_ptr, 0, 0);
fclose(fpin);
return false;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
fclose(fpin);
return false;
}
//---------------------------------------------------------------------
png_init_io(png_ptr, imgdata);
png_read_info(png_ptr, info_ptr);
//---------------------------------------------------------------------
png_byte colour_type = png_get_color_type(png_ptr, info_ptr);
png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
VC_IMAGE_TYPE_T type = VC_IMAGE_RGB888;
if (colour_type & PNG_COLOR_MASK_ALPHA)
{
type = VC_IMAGE_RGBA32;
}
initImage(image,
type,
png_get_image_width(png_ptr, info_ptr),
png_get_image_height(png_ptr, info_ptr),
false);
//---------------------------------------------------------------------
double gamma = 0.0;
if (png_get_gAMA(png_ptr, info_ptr, &gamma))
{
png_set_gamma(png_ptr, 2.2, gamma);
}
//---------------------------------------------------------------------
if (colour_type == PNG_COLOR_TYPE_PALETTE)
{
png_set_palette_to_rgb(png_ptr);
}
if ((colour_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8))
{
png_set_expand_gray_1_2_4_to_8(png_ptr);
}
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
{
png_set_tRNS_to_alpha(png_ptr);
}
if (bit_depth == 16)
{
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
png_set_scale_16(png_ptr);
#else
png_set_strip_16(png_ptr);
#endif
}
if (colour_type == PNG_COLOR_TYPE_GRAY ||
colour_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
png_set_gray_to_rgb(png_ptr);
}
//---------------------------------------------------------------------
png_read_update_info(png_ptr, info_ptr);
//---------------------------------------------------------------------
png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));
png_uint_32 j = 0;
for (j = 0 ; j < image->height ; ++j)
{
row_pointers[j] = image->buffer + (j * image->pitch);
}
//---------------------------------------------------------------------
png_read_image(png_ptr, row_pointers);
//---------------------------------------------------------------------
fclose(fpin);
free(row_pointers);
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
return true;
}
Edit : Image can be provided from python in raw RGBA, or in png format (as a string with header, and chunks). I suppose raw RGBA would faster (skipping png format), but the modifying this function may be more simple with PNG string ...
Any clue is welcome !
If you can get raw RGBA data then you don't need this function. This function is used to decode compressed png format to raw RGBA. The only thing you'd probably also need to provide is width and height.
The only question now is what would be more efficient - sending raw, uncompressed data to C program or encoding it in Python to PNG, sending encoded data and decoding it in C program.
The biggest issue here is the png_init_io(png_ptr, fpin); (I changed imgData to fpin in the function call, but you probably wanted to pass the array instead of the FILE handle). In libpng documentation in section 5 there's a description how to provide one's own functions for input/output. You'd have to substitute png_init_io with your own function taking const char* instead of FILE*. Here's a part on the png_init_io:
Input/Output in libpng is done through png_read() and png_write(), which currently just call fread() and fwrite(). The FILE * is stored in png_struct and is initialized via png_init_io(). If you wish to change the method of I/O, the library supplies callbacks that you can set through the function png_set_read_fn() and png_set_write_fn() at run time, instead of calling the png_init_io() function. These functions also provide a void pointer that can be retrieved via the function png_get_io_ptr(). For example:
png_set_read_fn(png_structp read_ptr,
voidp read_io_ptr, png_rw_ptr read_data_fn)
png_set_write_fn(png_structp write_ptr,
voidp write_io_ptr, png_rw_ptr write_data_fn,
png_flush_ptr output_flush_fn);
voidp read_io_ptr = png_get_io_ptr(read_ptr);
voidp write_io_ptr = png_get_io_ptr(write_ptr);
The replacement I/O functions must have prototypes as follows:
void user_read_data(png_structp png_ptr,
png_bytep data, png_size_t length);
void user_write_data(png_structp png_ptr,
png_bytep data, png_size_t length);
void user_flush_data(png_structp png_ptr);
I've never manipulated those functions so I can't help you here, but it seems that the only thing you'd have to change is skip opening the file and read the same chunks of data from the array as the original implementation does with a file. You'd have to read this section, probably check the source code to see what's to be done and think if it's worth the time if you have the possibility to get already decoded data.

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.

How do I get the DC coefficient from a jpg using the jpg library?

I am new to this stuff, but I need to get the dc-coefficient from a jpeg using the jpeg library?
I was told as a hint that the corresponding function is in jdhuff.c, but I can't find it. I tried to find a decent article about the jpg library where I can get this, but no success so far.
So I hope you guys can help me a bit and point me to either some documentation or have a hint.
So, here is what I know:
A jpg picture consists of 8x8 Blocks. That are 64 Pixels. 63 of it are named AC and 1 is named DC. Thats the coefficient. The position is at array[0][0].
But how do I exactly read that with the jpg library? I am using C++.
edit:
This is what I have so far:
read_jpeg::read_jpeg( const std::string& filename )
{
FILE* fp = NULL; // File-Pointer
jpeg_decompress_struct cinfo; // jpeg decompression parameters
JSAMPARRAY buffer; // Output row-buffer
int row_stride = 0; // physical row width
my_error_mgr jerr; // Custom Error Manager
// Set Error Manager
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
// Handle longjump
if (setjmp(jerr.setjmp_buffer)) {
// JPEG has signaled an error. Clean up and throw an exception.
jpeg_destroy_decompress(&cinfo);
fclose(fp);
throw std::runtime_error("Error: jpeg has reported an error.");
}
// Open the file
if ( (fp = fopen(filename.c_str(), "rb")) == NULL )
{
std::stringstream ss;
ss << "Error: Cannot read '" << filename.c_str() << "' from the specified location!";
throw std::runtime_error(ss.str());
}
// Initialize jpeg decompression
jpeg_create_decompress(&cinfo);
// Show jpeg where to read the data
jpeg_stdio_src(&cinfo, fp);
// Read the header
jpeg_read_header(&cinfo, TRUE);
// Decompress the file
jpeg_start_decompress(&cinfo);
// JSAMPLEs per row in output buffer
row_stride = cinfo.output_width * cinfo.output_components;
// Make a one-row-high sample array
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
// Read image using jpgs counter
while (cinfo.output_scanline < cinfo.output_height)
{
// Read the image
jpeg_read_scanlines(&cinfo, buffer, 1);
}
// Finish the decompress
jpeg_finish_decompress(&cinfo);
// Release memory
jpeg_destroy_decompress(&cinfo);
// Close the file
fclose(fp);
}
This is not possible using the standard API. With libjpeg API the closest you can get is raw pixel data of Y/Cb/Cr channels.
To get coefficients' data you'd need to hack the decode_mcu function (or its callers) to save the data decoded there.

Debug Assertion Failed

Using Visual Studio 2010, C++.
Programming level: beginner.
I have a code from a book Windows Game Programming Gurus and up until now have managed all problems i have stumbled upon.
But this i don't know what it is.
Here is a screenshot of an error:
That is one nice 8-bit image...
Now, it says File: f:\dd...
In my case f: drive is empty cd-rom...
This is the line where i think error is happening:
_lseek(file_handle, -((int) (bitmap->bitmapinfoheader.biSizeImage)), SEEK_END);
What is this thing?
The f:\dd directory is where the source code of the "C Runtime Library" (CRT) was located, when it was built. Since Microsoft built that, it doesn't correspond to your F: drive.
Anyway, the CRT detected that one of the file handles is wrong. You passed it to the CRT, so you should check why it's wrong. If you press Retry, you'll be put in the debugger. There you can see which of your functions put in the wrong file handle.
It won't tell you why the handle is wrong, though. A common reason is that you tried to open a file, and forgot to check if it succeeded. You only get a file handle if the file name is valid, and you're allowed to read that file.
The assertion happens in the C library. It makes sure you pass valid argument to the lseek() function.
You probably did not check for errors after doing open() or creat() on the file.
Looks like your file_handle is wrong. Are you sure the opening of your image succeeded ?
Full function code which uses C++ ifstream instead of low-level IO functions.
Jonathan and i tried to make _lseek work only to conclude that it doesn't work...
Don't know if that is entirely true, maybe there is some way it works correctly.
If you (the reader) know, feel free to message me.
The function now works, although main program displays image wrongly, but that is beside matter of this question, _lseek thing is solved :)
int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
{
int file_handle = 0; // the file handle
int index = 0; // looping index
int bitmapWidth = 0;
int bitmapHeight = 0;
int bitmapSize = 0;
UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
streampos pos_cur;
ifstream bitmapFile = ifstream ();
bitmapFile.open (filename, ifstream::in);
if (! bitmapFile.is_open ())
{
printError ("Error: OpenFile function failure. ");
// abort
return(0);
}
// load the bitmap file header:
//_lread(file_handle, &(bitmap->bitmapfileheader), sizeof(BITMAPFILEHEADER));
bitmapFile.read ((char *) &(bitmap->bitmapfileheader), sizeof (BITMAPFILEHEADER));
// test if this is a bitmap file
if (bitmap->bitmapfileheader.bfType != BITMAP_ID)
{
// close the file
//_lclose(file_handle);
bitmapFile.close ();
printError ("error: wrong bitmap type");
cout << "error: wrong bitmap type" << endl;
// return error
return(0);
} // end if
// now we know this is a bitmap, so read in all the sections.
if (bitmap->bitmapinfoheader.biSizeImage == 0)
printError ("error: biSizeImage equals 0");
// now the bitmap infoheader:
//_lread(file_handle, &bitmap->bitmapinfoheader, sizeof(BITMAPINFOHEADER));
bitmapFile.seekg (sizeof (BITMAPFILEHEADER), ios::beg);
pos_cur = bitmapFile.tellg (); // save current stream position
bitmapFile.read ((char *) &(bitmap->bitmapinfoheader), sizeof (BITMAPINFOHEADER));
//cout << bitmap->bitmapinfoheader.biBitCount << endl;
// now load the color palette if there is one
if (bitmap->bitmapinfoheader.biBitCount == 8)
{
//_lread(file_handle, &bitmap->palette, MAX_COLORS_PALETTE * sizeof(PALETTEENTRY));
// not tested:
bitmapFile.read ((char *) &(bitmap->palette), MAX_COLORS_PALETTE * sizeof(PALETTEENTRY));
// now set all the flags in the palette correctly and fix the reversed
// BGR RGBQUAD data format
for (index = 0; index < MAX_COLORS_PALETTE; index++)
{
// reverse the red and green fields
int temp_color = bitmap->palette[index].peRed;
bitmap->palette[index].peRed = bitmap->palette[index].peBlue;
bitmap->palette[index].peBlue = temp_color;
// always set the flags word to this
bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
} // end for index
} // end if
bitmapWidth = bitmap->bitmapinfoheader.biWidth * (bitmap->bitmapinfoheader.biBitCount / 8);
bitmapHeight = bitmap->bitmapinfoheader.biHeight;
bitmapSize = bitmapWidth * bitmapHeight;
// finally the image data itself:
//_lseek(file_handle, -((int) (bitmap->bitmapinfoheader.biSizeImage)), SEEK_END);
bitmapFile.seekg (-((int) bitmapSize), ios::end);
//bitmapFile.seekg (sizeof (BITMAPINFOHEADER) + sizeof (BITMAPFILEHEADER) + MAX_COLORS_PALETTE * sizeof(PALETTEENTRY), ios::beg);
// now read in the image, if the image is 8 or 16 bit then simply read it
// but if its 24 bit then read it into a temporary area and then convert
// it to a 16 bit image
if (bitmap->bitmapinfoheader.biBitCount == 8 ||
bitmap->bitmapinfoheader.biBitCount == 16 ||
bitmap->bitmapinfoheader.biBitCount == 24)
{
// delete the last image if there was one
if (bitmap->buffer)
free(bitmap->buffer);
// allocate the memory for the image
//if (!(bitmap->buffer = (UCHAR *) malloc (bitmap->bitmapinfoheader.biSizeImage))) // error: biSizeImage == 0 !
if (!(bitmap->buffer = (UCHAR *) malloc (bitmapSize)))
{
// close the file
//_lclose(file_handle);
bitmapFile.close ();
// return error
return(0);
} // end if
// now read it in
//_lread(file_handle, bitmap->buffer, bitmap->bitmapinfoheader.biSizeImage);
bitmapFile.read ((char *) (bitmap->buffer), bitmapSize);
} // end if
else
{
// serious problem
return(0);
} // end else
// close the file
//_lclose(file_handle);
bitmapFile.close ();
// flip the bitmap
Flip_Bitmap(bitmap->buffer,
bitmap->bitmapinfoheader.biWidth * (bitmap->bitmapinfoheader.biBitCount / 8),
bitmap->bitmapinfoheader.biHeight);
//cout << "biSizeImage: " << bitmap->bitmapinfoheader.biSizeImage << endl;
//cout << (bitmap->bitmapinfoheader.biWidth * (bitmap->bitmapinfoheader.biBitCount / 8)) * bitmap->bitmapinfoheader.biHeight << endl;
// return success
return(1);
} // end Load_Bitmap_File
///////////////////////////////////////////////////////////
Current full source code:
http://pastebin.com/QQ6fMD7P
Expiration date is set to never.
Thanks to all people contributing to this question!
lseek crashes with the debug assertion failed error because it is a 16bit function. I found this out by looking at a chart of 16bit and 32bit functions on the microsoft website.
Solution is to use _llseek. _llseek is a 32bit function and can run on 64bit computers.
You do not need to change any parameters from _lseek to use _llseek.
_lseek(file_handle, -((int) (bitmap->bitmapinfoheader.biSizeImage)), SEEK_END);
becomes
_llseek(file_handle, -((int) (bitmap->bitmapinfoheader.biSizeImage)), SEEK_END);