I try to insert some EXIF Data in a JPEG stream. I am using libexif for that.
The libexif example shows how to open a file -> add the data -> and then save the file. What I have is a pointer (void * JPEGPointer) to a JPEG stream. So I want to just add the from libexif generated data to this pointer for sending it via FTP. Not saving to a file. The following code is basically the example from libexif with some not working memcpy() attempts from myself. The JPG File is corrupted after the memcpy so i can not open it with any Software. I think i am copying the exif to the wrong position. I can not use any aditional library unfortunately.
// Set the image options
exif_data_set_option(exif, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
exif_data_set_data_type(exif, EXIF_DATA_TYPE_COMPRESSED);
exif_data_set_byte_order(exif, FILE_BYTE_ORDER);
// Create the mandatory EXIF fields with default data
exif_data_fix(exif);
/* Create a EXIF_TAG_USER_COMMENT tag. This one must be handled
* differently because that tag isn't automatically created and
* allocated by exif_data_fix(), nor can it be created using
* exif_entry_initialize() so it must be explicitly allocated here.
*/
entry = createTag(exif, EXIF_IFD_EXIF, EXIF_TAG_USER_COMMENT,
sizeof(ASCII_COMMENT) + sizeof(FILE_COMMENT) - 2);
/* Write the special header needed for a comment tag */
memcpy(entry->data, ASCII_COMMENT, sizeof(ASCII_COMMENT)-1);
/* Write the actual comment text, without the trailing NUL character */
memcpy(entry->data+8, FILE_COMMENT, sizeof(FILE_COMMENT)-1);
/* createTag() happens to set the format and components correctly for
* EXIF_TAG_USER_COMMENT, so there is nothing more to do. */
/* Get a pointer to the EXIF data block we just created */
exif_data_save_data(exif, &exif_data, &exif_data_len);
assert(exif_data != NULL);
//copy exif data to my JPEGPointer...not working like that
memcpy(JPEGPointer+ exif_data_len * sizeof(uint8_t), JPEGPointer, sizeof(JPEGPointer)+exif_data_len);
free(exif_data);
exif_data_unref(exif);
Any ideas how to put that EXIF data to the correct position in the JPEG data?
Related
damn i'm very frustated...
Following the example in this page http://support.dcmtk.org/docs/mod_dcmjpeg.html, I have written a C++ program to decompress a JPEG-compressed DICOM image file
Now I want to do the vice versa, from uncompressed to compressed and if I use the other example in the same page, with the same (or other file) the code compile and run but is not able to compress the file...
I saw that afetr the following code, the originale Xfer and the Current is the same, and this is not good because need to be different
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, ¶ms);
It's like the chooseRepresentation method fail....
More the line
dataset->canWriteXfer(EXS_JPEGProcess14SV1)
return false
I saw that in the dcpixel.cc file, with debugging the code go in
DcmPixelData::canChooseRepresentation(.........
....
....
// representation not found, check if we have a codec that can create the
// desired representation.
if (original == repListEnd)
{
result = DcmCodecList::canChangeCoding(EXS_LittleEndianExplicit, toType.getXfer());
}
and result is FALSE....
How can I fix it? Someone have a code that works to compress a DICOM image with DCMTK or another library
This is the full code:
int main()
{
//dcxfer.h
DJDecoderRegistration::registerCodecs(); // register JPEG codecs
DcmFileFormat fileformat;
/**** MONO FILE ******/
if (fileformat.loadFile("Files/cnv3DSlice (1)_cnv.dcm").good())
{
DcmDataset *dataset = fileformat.getDataset();
DcmItem *metaInfo = fileformat.getMetaInfo();
DJ_RPLossless params; // codec parameters, we use the defaults
// this causes the lossless JPEG version of the dataset to be created
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, ¶ms);
// check if everything went well
if (dataset->canWriteXfer(EXS_JPEGProcess14SV1))
{
// force the meta-header UIDs to be re-generated when storing the file
// since the UIDs in the data set may have changed
delete metaInfo->remove(DCM_MediaStorageSOPClassUID);
delete metaInfo->remove(DCM_MediaStorageSOPInstanceUID);
// store in lossless JPEG format
fileformat.saveFile("Files/test_jpeg_compresso.dcm", EXS_JPEGProcess14SV1);
}
}
DJDecoderRegistration::cleanup(); // deregister JPEG codecs
return 0;
}
When trying to compress an image you need to call
DJEncoderRegistration::registerCodecs();
Decompress is
DJDecoderRegistration::registerCodecs();
I got the problem with my program made for downloading the DateTimeOrginal data from the .JPG file. I found the document about it on the internet:
https://ExifTool.org/TagNames/EXIF.html
I see that the data I'm looking for is at 0x9003 address.
So right now what I'm trying to do is:
temp = fopen(name, "rb");
open the file binary
fseek (temp, 0x9003, SEEK_SET);
move the File pointer to the address
fscanf(temp, "%s", str);
and load the data to the char[] structure.
Is atleast any of that correct? I'm still thinking that i got the problem with the address, because after compile that program i see only some trash from the file.
The EXIF data is embedded into the jpeg tag APP1 (0xE1).
The first thing to do is to find the jpef tag 0xE1 in the stream; you have to scan all the jpeg tags (marked by 0xFF+tag, in your case 0xFF,0xE1). After you get the tag, find its length by reading the next 2 bytes (and adjust for high endian), then get the tag's content.
After you get the tag's content, then look in it for the EXIF tag you are interested in (0x9003).
The method readStream in the jpeg class of the open source project Imebra gives you an example on how to parse jpeg tags: https://bitbucket.org/binarno/imebra/src/2eb33b2170e76b5ad2737d1c2d81c1dcaccd19e5/project_files/library/imebra/src/jpegCodec.cpp?at=default#cl-867
Given the style of programming of the OP, I'd recommend Easyexif at https://github.com/mayanklahiri/easyexif
It's relatively easy to integrate. Note that fseek() goes to a file position; it does not search for a certain number.
Hi I have an image in my memory and I want to sent it through an external FTP library.
This FTP library accepts only and only standard C FILE and the sample codes provided by this library reads data only from hard disk. In my application I don't want to store my images in the hard disk and then read them using FILE variable, instead I want to do the conversion in my memory so it's faster and more professional.
My image is in the form of uchar * but I can change it to std::String or QByteArray or any other type of string. Now I want to know how can I have a file which is filled by my image data so I will get rid of storing it into the hard disk and read it again.
My pseudo code:
uchar * image = readImage();
FILE * New_Image = String2FileConverter(image); //I need this function
FTP_Upload(New_Image);
On Posix systems, you can use fmemopen to create a memory-backed file handle.
I want to write the header data of a JPEG image using jpeglib. Unfortunately, I am not exactly sure which header data I really do need. I am sure of:
- quantization table
- Huffman tables
- shared image info (I am not exactly sure which data this contains, somebody wrote about 5 unchangable bytes)
and I know that the usual header size should be 624 bytes.
My code looks like:
jpeg_mem_dest(&cinfo, &buffer, &bufferSize);
cinfo.image_width = imageWidth;
cinfo.image_height = imageHeight;
cinfo.input_components = inputComponents;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, false);
jpeg_write_tables(&cinfo);
jpeg_start_compress(&cinfo, false);
headerSize = bufferSize;
How to write only tables is taken from the jpeglib doc section "Abbreviated datastreams and multiple images".
Unfortunately, it writes only 574 bytes and when prepending the written header data to the image data without header it says "JPEG datastream contains no image" when trying to decompress it again.
Analysing an original file which uses a shared header I found the following markers:
markers found are:
FFD8 // Start Of Image
FFE0 // Application-specific
FFFE // Comment
FFDB // Define Quantization Table(s)
FFDB // Define Quantization Table(s)
FFC4 // Define Huffman Table(s)
FFC0 // Start Of Frame (Baseline DCT)
MIP maps (4 mip maps):
FFDA
FFD9
FFDA
FFD9
FFDA
FFD9
FFDA
FFD9
Descriptions are taken from
https://en.wikipedia.org/wiki/JPEG#Syntax_and_structure
From a comment in the original image I do even know the original JPEG compression lib:
Intel(R) JPEG Library, version 1,5,4,36
The point is I want to get the schema behind the format to write exactly the data which is required (apparently some essential image header information is missing otherwise it would at least find a JPEG image I guess).
In the reading process I always prepend the shared header to the image data of one single JPEG image.
I am trying to save the decoded image file back as a BMP image using the code in CUDA Decoder project.
if (g_bReadback && g_ReadbackSID)
{
CUresult result = cuMemcpyDtoHAsync(g_bFrameData[active_field], pDecodedFrame[active_field], (nDecodedPitch * nHeight * 3 / 2), g_ReadbackSID);
long padded_size = (nWidth * nHeight * 3 );
CString output_file;
output_file.Format(_T("image/sample_45.BMP"));
SaveBMP(g_bFrameData[active_field],nWidth,nHeight,padded_size,output_file );
if (result != CUDA_SUCCESS)
{
printf("cuMemAllocHost returned %d\n", (int)result);
}
}
But the saved image looks like this
Can anybody help me out here what am i doing wrong .. Thank you.
After investigating further, there were several modifications I made to your approach.
pDecodedFrame is actually in some non-RGB format, I think it is NV12 format which I believe is a particular YUV variant.
pDecodedFrame gets converted to an RGB format on the GPU using a particular CUDA kernel
the target buffer for this conversion will either be a surface provided by OpenGL if g_bUseInterop is specified, or else an ordinary region allocated by the driver API version of cudaMalloc if interop is not specified.
The target buffer mentioned above is pInteropFrame (even in the non-interop case). So to make an example for you, for simplicity I chose to only use the non-interop case, because it's much easier to grab the RGB buffer (pInteropFrame) in that case.
The method here copies pInteropFrame back to the host, after it has been populated with the appropriate RGB image by cudaPostProcessFrame. There is also a routine to save the image as a bitmap file. All of my modifications are delineated with comments that include RMC so search for that if you want to find all the changes/additions I made.
To use, drop this file in the cudaDecodeGL project as a replacement for the videoDecodeGL.cpp source file. Then rebuild the project. Then run the executable normally to display the video. To capture a specific frame, run the executable with the nointerop command-line switch, eg. cudaDecodGL nointerop and the video will not display, but the decode operation and frame capture will take place, and the frame will be saved in a framecap.bmp file. If you want to change the specific frame number that is captured, modify the g_FrameCapSelect = 37; variable to some other number besides 37, and recompile.
Here is the replacement for videoDecodeGL.cpp I used pastebin because SO has a limit on the number of characters that can be entered in a question body.
Note that my approach is independent of whether readback is specified. I would recommend not using readback for this sequence.