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

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.

Related

libpng error invalid chunk type when loading png from memory

I'm trying to load a PNG from a memory buffer so I can access the ImageData without having to save it as a file first.
The memory buffer contains a valid png-file, when using fwrite to save it as a file on disk I get the following image: https://dl.dropboxusercontent.com/u/13077624/test.png
This represents a depth Image received by a Kinect sensor, for those of you wondering.
This is the code that gives errors:
struct mem_encode
{
char *buffer;
png_uint_32 size;
png_uint_32 current_pos;
};
void handle_data(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
cout<<"Saving as file: "<<determinePathExtension(PNGFrame,"png");
FILE* fp=fopen("test.png","wb");
fwrite(data_,bytes_transferred,1,fp);
fclose(fp);
//get PNG file info struct (memory is allocated by libpng)
png_structp png_ptr = NULL;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
std::cerr << "ERROR: Couldn't initialize png read struct" << std::endl;
cin.get();
return; //Do your own error recovery/handling here
}
// get PNG image data info struct (memory is allocated by libpng)
png_infop info_ptr = NULL;
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
std::cerr << "ERROR: Couldn't initialize png info struct" << std::endl;
cin.get();
png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
return; //Do your own error recovery/handling here
}
struct mem_encode pngdata;
pngdata.buffer=data_;
pngdata.size=(png_uint_32)bytes_transferred;
pngdata.current_pos=0;
png_set_read_fn(png_ptr,&pngdata, ReadData);
//Start reading the png header
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr,info_ptr);
//... Program crashes here
}
else
{
cout<<error.message()<<" Bytes received: "<<bytes_transferred<<endl;
delete this;
}
}
static void ReadData(png_structp png_ptr, png_bytep outBytes,
png_size_t byteCountToRead){
struct mem_encode* p=(struct mem_encode*)png_get_io_ptr(png_ptr);
size_t nsize=p->size + byteCountToRead;
if(byteCountToRead>(p->size-p->current_pos)) png_error(png_ptr,"read error in read_data_memory (loadpng)");
/* copy new bytes */
memcpy(outBytes,p->buffer + p->size,byteCountToRead);
p->current_pos+=byteCountToRead;
}
Calling the method results in the program crashing with the following error:
libpng error: [00][00][00][00]: invalid chunk type
data_ represents the the databuffer storing the PNG-image and is a char *.
Any help would be appreciated.
Sources I used:
http://www.libpng.org/pub/png/libpng-1.0.3-manual.html
http://blog.hammerian.net/2009/reading-png-images-from-memory/
http://santosdev.blogspot.be/2012/08/loading-png-image-with-libpng-1512-or.html
http://www.piko3d.net/tutorials/libpng-tutorial-loading-png-files-from-streams/
Could this be caused by network bytes being translated badly?
I think you forgot to read the PNG signature bytes. Use
if (png_sig_cmp(data, 0, 8)
png_error(png_ptr, "it's not a PNG file");
Then your
png_set_sig_bytes(png_ptr,8);
lets libpng know you have already read the signature.
Or, you could use png_set_sig_bytes(png_ptr, 0); and
let libpng do the checking for you.
Are you sure your ReadData function is correct? Why do you start memcpy from the address p->buffer + p->size - isn't it the end of the buffer? And what does nsize do?

How to read YUV8 data from avi file?

I have avi file that contains uncompressed gray video data. I need to extract frames from it. The size of file is 22 Gb.
How do i do that?
I have already tried ffmpeg, but it gives me "could not find codec parameters for video stream" message - because there is no codec at work, just frames.
Since Opencv just uses ffmpeg to read video, that rules out opencv as well.
The only path that seems to be left is to try and dig into the raw data, but i do not know how.
Edit: this is the code i use to read from the file with opencv. The failure occurs inside the second if. Running ffmpeg binary on the file also fails with the message above (could not find codec aprameters etc)
/* register all formats and codecs */
av_register_all();
/* open input file, and allocate format context */
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
fprintf(stderr, "Could not open source file %s\n", src_filename);
ret = 1;
goto end;
}
fmt_ctx->seek2any = true;
/* retrieve stream information */
int res = avformat_find_stream_info(fmt_ctx, NULL);
if (res < 0) {
fprintf(stderr, "Could not find stream information\n");
ret = 1;
goto end;
}
Edit:
Here is sample code i have tried to make the extraction: pastebin. The result i get is an unchanging buffer after every call to AVIStreamRead.
If you do not need cross platform functionality Video for Windows (VFW) API is a good alternative (http://msdn.microsoft.com/en-us/library/windows/desktop/dd756808(v=vs.85).aspx), i will not put an entire code block, since there's quite much to do, but you should be able to figure it out from the reference link. Basically, you do a AVIFileOpen, then get the video stream via AVIFileGetStream with streamtypeVIDEO, or alternatively do it at once with AVIStreamOpenFromFile and then read samples from the stream with AVIStreamRead. If you get to a point where you fail I can try to help, but it should be pretty straightforward.
Also, not sure why ffmpeg is failing, I have been doing raw AVI reading with ffmpeg without any codecs involved, can you post what call to ffpeg actually fails?
EDIT:
For the issue that you are seeing when the read data size is 0. The AVI file has N slots for frames in each second where N is the fps of the video. In real life the samples won't come exactly at that speed (e.g. IP surveillance cameras) so the actual data sample indexes can be non continuous like 1,5,11,... and VFW would insert empty samples between them (that is from where you read a sample with a zero size). What you have to do is call AVIStreamRead with NULL as buffer and 0 as size until the bRead is not 0 or you run past last sample. When you get an actual size, then you can again call AVIStreamRead on that sample index with the buffer pointer and size. I usually do compressed video so i don't use the suggested size, but at least according to your code snipplet I would do something like this:
...
bRead = 0;
do
{
aviOpRes = AVIStreamRead(ppavi,smpS,1,NULL,0,&bRead,&smpN);
} while (bRead == 0 && ++smpS < si.dwLength + si.dwStart);
if(smpS >= si.dwLength + si.dwStart)
break;
PUCHAR tempBuffer = new UCHAR[bRead];
aviOpRes = AVIStreamRead(ppavi,smpS,1,tempBuffer,bRead,&bRead,&smpN);
/* do whatever you need */
delete tempBuffer;
...
EDIT 2:
Since this may come in handy to someone or yourself to make a choice between VFW and FFMPEG I also updated your FFMPEG example so that it parsed the same file (sorry for the code quality since it lacks error checking but i guess you can see the logical flow):
/* register all formats and codecs */
av_register_all();
AVFormatContext* fmt_ctx = NULL;
/* open input file, and allocate format context */
const char *src_filename = "E:\\Output.avi";
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
fprintf(stderr, "Could not open source file %s\n", src_filename);
abort();
}
/* retrieve stream information */
int res = avformat_find_stream_info(fmt_ctx, NULL);
if (res < 0) {
fprintf(stderr, "Could not find stream information\n");
abort();
}
int video_stream_index = 0; /* video stream is usualy 0 but still better to lookup in case it's not present */
for(; video_stream_index < fmt_ctx->nb_streams; ++video_stream_index)
{
if(fmt_ctx->streams[video_stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
break;
}
if(video_stream_index == fmt_ctx->nb_streams)
abort();
AVPacket *packet = new AVPacket;
while(av_read_frame(fmt_ctx, packet) == 0)
{
if (packet->stream_index == video_stream_index)
printf("Sample nr %d\n", packet->pts);
av_free_packet(packet);
}
Basically you open the context and read packets from it. You will get both audio and video packets so you should check if the packet belongs to the stream of interest. FFMPEG will save you the trouble with empty frames and give only those samples that have data in them.

Load jpeg image texture with libjpeg from QByteArray

Hi I have a QByteArray of a jpeg image which I obtained from a QNetworkReply. I see everywhere jpeg image read from file and decompressed like this,
FILE * infile;
......
if ((infile = fopen(filename, "rb")) == NULL)
{
fprintf(stderr, "can't open %s\n", filename);
exit(1);
}
jpeg_stdio_src(&cinfo, infile);
jpeg_read_header(&cinfo, 0);
jpeg_start_decompress(&cinfo);
Then
while (scan lines remain to be read)
jpeg_read_scanlines(...);
But how do I read it from the QByteArray instead of a file/stdio stream?
Use
void jpeg_mem_src(j_decompress_ptr cinfo, unsigned char * inbuffer,
unsigned long insize);
instead of jpeg_stdio_src
QByteArray qarr;
jpeg_decompress_struct cinfo;
jpeg_mem_src(&cinfo, qarr.data(), qarr.size());
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
/// etc..
You don't need to use external jpeg library:
QByteArray array;
// read data into array here;
QPixmap image;
image.loadFromData(array);
should be enough. Qt will autodetect the image format. Just remember to distribute Qt jpeg plugin if you compile your application dynamically.

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

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