Ejemplo n.º 1
0
/**
   Write a chunk in a PNG stream from the current position.
   @param chunk_name Name of the chunk
   @param chunk_data Chunk array
   @param length Chunk length
   @param hPngMemory PNG stream handle
*/
static void
mng_WriteChunk(BYTE *chunk_name, BYTE *chunk_data, DWORD length, FIMEMORY *hPngMemory) {
    DWORD crc_file = 0;
    // write a PNG chunk ...
    // - length
    mng_SwapLong(&length);
    FreeImage_WriteMemory(&length, 1, 4, hPngMemory);
    mng_SwapLong(&length);
    // - chunk name
    FreeImage_WriteMemory(chunk_name, 1, 4, hPngMemory);
    if(chunk_data && length) {
        // - chunk data
        FreeImage_WriteMemory(chunk_data, 1, length, hPngMemory);
        // - crc
        crc_file = FreeImage_ZLibCRC32(0, chunk_name, 4);
        crc_file = FreeImage_ZLibCRC32(crc_file, chunk_data, length);
        mng_SwapLong(&crc_file);
        FreeImage_WriteMemory(&crc_file, 1, 4, hPngMemory);
    } else {
        // - crc
        crc_file = FreeImage_ZLibCRC32(0, chunk_name, 4);
        mng_SwapLong(&crc_file);
        FreeImage_WriteMemory(&crc_file, 1, 4, hPngMemory);
    }

}
Ejemplo n.º 2
0
// Takes an image from the frame buffer and compresses it
int writeFrame(FIMEMORY *fiBuffer, FIBITMAP *fiImage, unsigned char imageType) {
	/*
	char msg[1024];
	sprintf_s(msg, 1024, "imageType: %i", imageType);
	MessageBox(NULL,msg,"ADES DEBUG", MB_OK);
	*/
	imageType = 2;
	int errStatus = 1;
	u_short imageWidth, imageHeight;

	unsigned width, height, pitch, line;
	BYTE *bits;

	// Package image using correct compression
	switch(imageType) {
	case 0: // Send a raw frame
		// Get image characteristics
		width = FreeImage_GetWidth(fiImage);
		height = FreeImage_GetHeight(fiImage);
		pitch = FreeImage_GetPitch(fiImage);
		line = FreeImage_GetLine(fiImage);

		// Write out width and height
		errStatus = FreeImage_SeekMemory(fiBuffer, 0, SEEK_SET);
		if (errStatus != 1) break;

		imageWidth = htons(width);
		errStatus = FreeImage_WriteMemory( &imageWidth, 2, 1, fiBuffer );
		if (errStatus != 1) break;
		
		imageHeight = htons(height);
		errStatus = FreeImage_WriteMemory( &imageHeight, 2, 1, fiBuffer );
		if (errStatus != 1) break;

		// Write out image (convert the bitmap to raw bits, top-left pixel first)
		bits = (BYTE*)malloc(height * pitch);
		FreeImage_ConvertToRawBits(bits, fiImage, pitch, 24, 
			FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, TRUE);
		errStatus = FreeImage_WriteMemory( bits, height*pitch*sizeof(BYTE), 1, fiBuffer );
		free(bits);
		if (errStatus != 1) break;
		
		break;
	default: // Send a jpg frame
		errStatus = FreeImage_SeekMemory(fiBuffer, 0, SEEK_SET);
		if (errStatus != 1) break;

		errStatus = FreeImage_SaveToMemory(FIF_JPEG, fiImage, fiBuffer, convertToJpegFlag(imageType));
		if (errStatus != 1) break;
		break;
	}
	
	// Clean up and exit
	return errStatus;
}
Ejemplo n.º 3
0
/**
   Wrap a IDAT chunk as a PNG stream.
   The stream has the structure { g_png_signature, IHDR, IDAT, IEND }
   The image is assumed to be a greyscale image.

   @param jng_width Image width
   @param jng_height Image height
   @param jng_alpha_sample_depth Bits per pixel
   @param mChunk PNG grayscale IDAT format
   @param mLength IDAT chunk length
   @param hPngMemory Output memory stream
*/
static void
mng_WritePNGStream(DWORD jng_width, DWORD jng_height, BYTE jng_alpha_sample_depth, BYTE *mChunk, DWORD mLength, FIMEMORY *hPngMemory) {
    // PNG grayscale IDAT format

    BYTE data[14];

    // wrap the IDAT chunk as a PNG stream

    // write PNG file signature
    FreeImage_WriteMemory(g_png_signature, 1, 8, hPngMemory);

    // write a IHDR chunk ...
    /*
      The IHDR chunk must appear FIRST. It contains:
      Width:              4 bytes
      Height:             4 bytes
      Bit depth:          1 byte
      Color type:         1 byte
      Compression method: 1 byte
      Filter method:      1 byte
      Interlace method:   1 byte
    */
    // - chunk data
    mng_SwapLong(&jng_width);
    mng_SwapLong(&jng_height);
    memcpy(&data[0], &jng_width, 4);
    memcpy(&data[4], &jng_height, 4);
    mng_SwapLong(&jng_width);
    mng_SwapLong(&jng_height);
    data[8] = jng_alpha_sample_depth;
    data[9] = 0;    // color_type gray (jng_color_type)
    data[10] = 0;   // compression method 0 (jng_alpha_compression_method)
    data[11] = 0;   // filter_method 0 (jng_alpha_filter_method)
    data[12] = 0;   // interlace_method 0 (jng_alpha_interlace_method)

    mng_WriteChunk(mng_IHDR, &data[0], 13, hPngMemory);

    // write a IDAT chunk ...
    mng_WriteChunk(mng_IDAT, mChunk, mLength, hPngMemory);

    // write a IEND chunk ...
    mng_WriteChunk(mng_IEND, NULL, 0, hPngMemory);

}
Ejemplo n.º 4
0
/**
   Insert a chunk just before the inNextChunkName chunk
   @param hPngMemory PNG stream handle
   @param start_pos Start position of the inNextChunkName chunk
   @param next_pos Start position of the next chunk
   @return Returns TRUE if successfull, returns FALSE otherwise
*/
static BOOL
mng_CopyInsertChunks(FIMEMORY *hPngMemory, BYTE *inNextChunkName, BYTE *inInsertChunk, DWORD inChunkLength, DWORD start_pos, DWORD next_pos) {
    BYTE *data = NULL;
    DWORD size_in_bytes = 0;

    // length of the chunk to check
    DWORD chunk_length = next_pos - start_pos;
    if(chunk_length == 0) {
        return TRUE;
    }

    // get a pointer to the stream buffer
    FreeImage_AcquireMemory(hPngMemory, &data, &size_in_bytes);
    if(!(data && size_in_bytes) || (size_in_bytes < 20) || (chunk_length >= size_in_bytes)) {
        // not enough space to read a signature(8 bytes) + a chunk(at least 12 bytes)
        return FALSE;
    }

    // new file length
    unsigned buffer_size = inChunkLength + size_in_bytes;

    BYTE *buffer = (BYTE*)malloc(buffer_size * sizeof(BYTE));
    if(!buffer) {
        return FALSE;
    }
    unsigned p = 0;
    memcpy(&buffer[p], &data[0], start_pos);
    p += start_pos;
    memcpy(&buffer[p], inInsertChunk, inChunkLength);
    p += inChunkLength;
    memcpy(&buffer[p], &data[start_pos], size_in_bytes - start_pos);

    // seek to the start of the stream
    FreeImage_SeekMemory(hPngMemory, 0, SEEK_SET);
    // re-write the stream
    FreeImage_WriteMemory(buffer, 1, buffer_size, hPngMemory);

    free(buffer);

    return TRUE;
}
Ejemplo n.º 5
0
unsigned fipMemoryIO::write(const void *buffer, unsigned size, unsigned count) {
	return FreeImage_WriteMemory(buffer, size, count, _hmem);
}
Ejemplo n.º 6
0
/**
Output function. Should return 1 if writing was successful.
data/data_size is the segment of data to write, and 'picture' is for
reference (and so one can make use of picture->custom_ptr).
*/
static int 
WebP_MemoryWriter(const BYTE *data, size_t data_size, const WebPPicture* const picture) {
	FIMEMORY *hmem = (FIMEMORY*)picture->custom_ptr;
	return data_size ? (FreeImage_WriteMemory(data, 1, (unsigned)data_size, hmem) == data_size) : 0;
}
Ejemplo n.º 7
0
/**
   Load a FIBITMAP from a MNG or a JNG stream
   @param format_id ID of the caller
   @param io Stream i/o functions
   @param handle Stream handle
   @param Offset Start of the first chunk
   @param flags Loading flags
   @return Returns a dib if successful, returns NULL otherwise
*/
FIBITMAP*
mng_ReadChunks(int format_id, FreeImageIO *io, fi_handle handle, long Offset, int flags = 0) {
    DWORD mLength = 0;
    BYTE mChunkName[5];
    BYTE *mChunk = NULL;
    DWORD crc_file;
    long LastOffset;
    long mOrigPos;
    BYTE *PLTE_file_chunk = NULL;   // whole PLTE chunk (lentgh, name, array, crc)
    DWORD PLTE_file_size = 0;       // size of PLTE chunk

    BOOL m_HasGlobalPalette = FALSE; // may turn to TRUE in PLTE chunk
    unsigned m_TotalBytesOfChunks = 0;
    FIBITMAP *dib = NULL;
    FIBITMAP *dib_alpha = NULL;

    FIMEMORY *hJpegMemory = NULL;
    FIMEMORY *hPngMemory = NULL;
    FIMEMORY *hIDATMemory = NULL;

    // ---
    DWORD jng_width = 0;
    DWORD jng_height = 0;
    BYTE jng_color_type = 0;
    BYTE jng_image_sample_depth = 0;
    BYTE jng_image_compression_method = 0;

    BYTE jng_alpha_sample_depth = 0;
    BYTE jng_alpha_compression_method = 0;
    BYTE jng_alpha_filter_method = 0;
    BYTE jng_alpha_interlace_method = 0;

    DWORD mng_frame_width = 0;
    DWORD mng_frame_height = 0;
    DWORD mng_ticks_per_second = 0;
    DWORD mng_nominal_layer_count = 0;
    DWORD mng_nominal_frame_count = 0;
    DWORD mng_nominal_play_time = 0;
    DWORD mng_simplicity_profile = 0;


    DWORD res_x = 2835; // 72 dpi
    DWORD res_y = 2835; // 72 dpi
    RGBQUAD rgbBkColor = {0, 0, 0, 0};
    WORD bk_red, bk_green, bk_blue;
    BOOL hasBkColor = FALSE;
    BOOL mHasIDAT = FALSE;

    tEXtMAP key_value_pair;

    // ---

    BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

    // get the file size
    const long mLOF = mng_LOF(io, handle);
    // go to the first chunk
    io->seek_proc(handle, Offset, SEEK_SET);

    try {
        BOOL mEnd = FALSE;

        while(mEnd == FALSE) {
            // start of the chunk
            LastOffset = io->tell_proc(handle);
            // read length
            mLength = 0;
            io->read_proc(&mLength, 1, sizeof(mLength), handle);
            mng_SwapLong(&mLength);
            // read name
            io->read_proc(&mChunkName[0], 1, 4, handle);
            mChunkName[4] = '\0';

            if(mLength > 0) {
                mChunk = (BYTE*)realloc(mChunk, mLength);
                if(!mChunk) {
                    FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: out of memory", mChunkName);
                    throw (const char*)NULL;
                }
                Offset = io->tell_proc(handle);
                if(Offset + (long)mLength > mLOF) {
                    FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: unexpected end of file", mChunkName);
                    throw (const char*)NULL;
                }
                // read chunk
                io->read_proc(mChunk, 1, mLength, handle);
            }
            // read crc
            io->read_proc(&crc_file, 1, sizeof(crc_file), handle);
            mng_SwapLong(&crc_file);
            // check crc
            DWORD crc_check = FreeImage_ZLibCRC32(0, &mChunkName[0], 4);
            crc_check = FreeImage_ZLibCRC32(crc_check, mChunk, mLength);
            if(crc_check != crc_file) {
                FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: bad CRC", mChunkName);
                throw (const char*)NULL;
            }

            switch( mng_GetChunckType(mChunkName) ) {
                case MHDR:
                    // The MHDR chunk is always first in all MNG datastreams except for those
                    // that consist of a single PNG or JNG datastream with a PNG or JNG signature.
                    if(mLength == 28) {
                        memcpy(&mng_frame_width, &mChunk[0], 4);
                        memcpy(&mng_frame_height, &mChunk[4], 4);
                        memcpy(&mng_ticks_per_second, &mChunk[8], 4);
                        memcpy(&mng_nominal_layer_count, &mChunk[12], 4);
                        memcpy(&mng_nominal_frame_count, &mChunk[16], 4);
                        memcpy(&mng_nominal_play_time, &mChunk[20], 4);
                        memcpy(&mng_simplicity_profile, &mChunk[24], 4);

                        mng_SwapLong(&mng_frame_width);
                        mng_SwapLong(&mng_frame_height);
                        mng_SwapLong(&mng_ticks_per_second);
                        mng_SwapLong(&mng_nominal_layer_count);
                        mng_SwapLong(&mng_nominal_frame_count);
                        mng_SwapLong(&mng_nominal_play_time);
                        mng_SwapLong(&mng_simplicity_profile);

                    } else {
                        FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: size is %d instead of 28", mChunkName, mLength);
                    }
                    break;

                case MEND:
                    mEnd = TRUE;
                    break;

                case LOOP:
                case ENDL:
                    break;
                case DEFI:
                    break;
                case SAVE:
                case SEEK:
                case TERM:
                    break;
                case BACK:
                    break;

                    // Global "PLTE" and "tRNS" (if any).  PNG "PLTE" will be of 0 byte, as it uses global data.
                case PLTE:  // Global
                    m_HasGlobalPalette = TRUE;
                    PLTE_file_size = mLength + 12; // (lentgh, name, array, crc) = (4, 4, mLength, 4)
                    PLTE_file_chunk = (BYTE*)realloc(PLTE_file_chunk, PLTE_file_size);
                    if(!PLTE_file_chunk) {
                        FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: out of memory", mChunkName);
                        throw (const char*)NULL;
                    } else {
                        mOrigPos = io->tell_proc(handle);
                        // seek to the start of the chunk
                        io->seek_proc(handle, LastOffset, SEEK_SET);
                        // load the whole chunk
                        io->read_proc(PLTE_file_chunk, 1, PLTE_file_size, handle);
                        // go to the start of the next chunk
                        io->seek_proc(handle, mOrigPos, SEEK_SET);
                    }
                    break;

                case tRNS:  // Global
                    break;

                case IHDR:
                    Offset = LastOffset;
                    // parse the PNG file and get its file size
                    if(mng_CountPNGChunks(io, handle, Offset, &m_TotalBytesOfChunks) == FALSE) {
                        // reach an unexpected end of file
                        mEnd = TRUE;
                        FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: unexpected end of PNG file", mChunkName);
                        break;
                    }

                    // wrap the { IHDR, ..., IEND } chunks as a PNG stream
                    if(hPngMemory == NULL) {
                        hPngMemory = FreeImage_OpenMemory();
                    }

                    mOrigPos = io->tell_proc(handle);

                    // write PNG file signature
                    FreeImage_SeekMemory(hPngMemory, 0, SEEK_SET);
                    FreeImage_WriteMemory(g_png_signature, 1, 8, hPngMemory);

                    mChunk = (BYTE*)realloc(mChunk, m_TotalBytesOfChunks);
                    if(!mChunk) {
                        FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: out of memory", mChunkName);
                        throw (const char*)NULL;
                    }

                    // on calling CountPNGChunks earlier, we were in Offset pos,
                    // go back there
                    io->seek_proc(handle, Offset, SEEK_SET);
                    io->read_proc(mChunk, 1, m_TotalBytesOfChunks, handle);
                    // Put back to original pos
                    io->seek_proc(handle, mOrigPos, SEEK_SET);
                    // write the PNG chunks
                    FreeImage_WriteMemory(mChunk, 1, m_TotalBytesOfChunks, hPngMemory);

                    // plug in global PLTE if local PLTE exists
                    if(m_HasGlobalPalette) {
                        // ensure we remove some local chunks, so that global
                        // "PLTE" can be inserted right before "IDAT".
                        mng_RemoveChunk(hPngMemory, mng_PLTE);
                        mng_RemoveChunk(hPngMemory, mng_tRNS);
                        mng_RemoveChunk(hPngMemory, mng_bKGD);
                        // insert global "PLTE" chunk in its entirety before "IDAT"
                        mng_InsertChunk(hPngMemory, mng_IDAT, PLTE_file_chunk, PLTE_file_size);
                    }

                    if(dib) FreeImage_Unload(dib);
                    dib = mng_LoadFromMemoryHandle(hPngMemory, flags);

                    // stop after the first image
                    mEnd = TRUE;
                    break;

                case JHDR:
                    if(mLength == 16) {
                        memcpy(&jng_width, &mChunk[0], 4);
                        memcpy(&jng_height, &mChunk[4], 4);
                        mng_SwapLong(&jng_width);
                        mng_SwapLong(&jng_height);

                        jng_color_type = mChunk[8];
                        jng_image_sample_depth = mChunk[9];
                        jng_image_compression_method = mChunk[10];
                        //BYTE jng_image_interlace_method = mChunk[11]; // for debug only

                        jng_alpha_sample_depth = mChunk[12];
                        jng_alpha_compression_method = mChunk[13];
                        jng_alpha_filter_method = mChunk[14];
                        jng_alpha_interlace_method = mChunk[15];
                    } else {
                        FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: invalid chunk length", mChunkName);
                        throw (const char*)NULL;
                    }
                    break;

                case JDAT:
                    if(hJpegMemory == NULL) {
                        hJpegMemory = FreeImage_OpenMemory();
                    }
                    // as there may be several JDAT chunks, concatenate them
                    FreeImage_WriteMemory(mChunk, 1, mLength, hJpegMemory);
                    break;

                case IDAT:
                    if(!header_only && (jng_alpha_compression_method == 0)) {
                        // PNG grayscale IDAT format
                        if(hIDATMemory == NULL) {
                            hIDATMemory = FreeImage_OpenMemory();
                            mHasIDAT = TRUE;
                        }
                        // as there may be several IDAT chunks, concatenate them
                        FreeImage_WriteMemory(mChunk, 1, mLength, hIDATMemory);
                    }
                    break;

                case IEND:
                    if(!hJpegMemory) {
                        mEnd = TRUE;
                        break;
                    }
                    // load the JPEG
                    if(dib) {
                        FreeImage_Unload(dib);
                    }
                    dib = mng_LoadFromMemoryHandle(hJpegMemory, flags);

                    // load the PNG alpha layer
                    if(mHasIDAT) {
                        BYTE *data = NULL;
                        DWORD size_in_bytes = 0;

                        // get a pointer to the IDAT buffer
                        FreeImage_AcquireMemory(hIDATMemory, &data, &size_in_bytes);
                        if(data && size_in_bytes) {
                            // wrap the IDAT chunk as a PNG stream
                            if(hPngMemory == NULL) {
                                hPngMemory = FreeImage_OpenMemory();
                            }
                            mng_WritePNGStream(jng_width, jng_height, jng_alpha_sample_depth, data, size_in_bytes, hPngMemory);
                            // load the PNG
                            if(dib_alpha) {
                                FreeImage_Unload(dib_alpha);
                            }
                            dib_alpha = mng_LoadFromMemoryHandle(hPngMemory, flags);
                        }
                    }
                    // stop the parsing
                    mEnd = TRUE;
                    break;

                case JDAA:
                    break;

                case gAMA:
                    break;

                case pHYs:
                    // unit is pixels per meter
                    memcpy(&res_x, &mChunk[0], 4);
                    mng_SwapLong(&res_x);
                    memcpy(&res_y, &mChunk[4], 4);
                    mng_SwapLong(&res_y);
                    break;

                case bKGD:
                    memcpy(&bk_red, &mChunk[0], 2);
                    mng_SwapShort(&bk_red);
                    rgbBkColor.rgbRed = (BYTE)bk_red;
                    memcpy(&bk_green, &mChunk[2], 2);
                    mng_SwapShort(&bk_green);
                    rgbBkColor.rgbGreen = (BYTE)bk_green;
                    memcpy(&bk_blue, &mChunk[4], 2);
                    mng_SwapShort(&bk_blue);
                    rgbBkColor.rgbBlue = (BYTE)bk_blue;
                    hasBkColor = TRUE;
                    break;

                case tEXt:
                    mng_SetMetadata_tEXt(key_value_pair, mChunk, mLength);
                    break;

                case UNKNOWN_CHUNCK:
                default:
                    break;


            } // switch( GetChunckType )
        } // while(!mEnd)

        FreeImage_CloseMemory(hJpegMemory);
        FreeImage_CloseMemory(hPngMemory);
        FreeImage_CloseMemory(hIDATMemory);
        free(mChunk);
        free(PLTE_file_chunk);

        // convert to 32-bit if a transparent layer is available
        if(!header_only && dib_alpha) {
            FIBITMAP *dst = FreeImage_ConvertTo32Bits(dib);
            if((FreeImage_GetBPP(dib_alpha) == 8) && (FreeImage_GetImageType(dib_alpha) == FIT_BITMAP)) {
                FreeImage_SetChannel(dst, dib_alpha, FICC_ALPHA);
            } else {
                FIBITMAP *dst_alpha = FreeImage_ConvertTo8Bits(dib_alpha);
                FreeImage_SetChannel(dst, dst_alpha, FICC_ALPHA);
                FreeImage_Unload(dst_alpha);
            }
            FreeImage_Unload(dib);
            dib = dst;
        }
        FreeImage_Unload(dib_alpha);

        if(dib) {
            // set metadata
            FreeImage_SetDotsPerMeterX(dib, res_x);
            FreeImage_SetDotsPerMeterY(dib, res_y);
            if(hasBkColor) {
                FreeImage_SetBackgroundColor(dib, &rgbBkColor);
            }
            if(key_value_pair.size()) {
                for(tEXtMAP::iterator j = key_value_pair.begin(); j != key_value_pair.end(); j++) {
                    std::string key = (*j).first;
                    std::string value = (*j).second;
                    mng_SetKeyValue(FIMD_COMMENTS, dib, key.c_str(), value.c_str());
                }
            }
        }

        return dib;

    } catch(const char *text) {
        FreeImage_CloseMemory(hJpegMemory);
        FreeImage_CloseMemory(hPngMemory);
        FreeImage_CloseMemory(hIDATMemory);
        free(mChunk);
        free(PLTE_file_chunk);
        FreeImage_Unload(dib);
        FreeImage_Unload(dib_alpha);
        if(text) {
            FreeImage_OutputMessageProc(format_id, text);
        }
        return NULL;
    }
}
Ejemplo n.º 8
0
/**
   Write a FIBITMAP to a JNG stream
   @param format_id ID of the caller
   @param io Stream i/o functions
   @param dib Image to be saved
   @param handle Stream handle
   @param flags Saving flags
   @return Returns TRUE if successful, returns FALSE otherwise
*/
BOOL
mng_WriteJNG(int format_id, FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int flags) {
    DWORD jng_width = 0;
    DWORD jng_height = 0;
    BYTE jng_color_type = 0;
    BYTE jng_image_sample_depth = 8;
    BYTE jng_image_compression_method = 8;  //  8: ISO-10918-1 Huffman-coded baseline JPEG.
    BYTE jng_image_interlace_method = 0;

    BYTE jng_alpha_sample_depth = 0;
    BYTE jng_alpha_compression_method = 0;
    BYTE jng_alpha_filter_method = 0;
    BYTE jng_alpha_interlace_method = 0;

    BYTE buffer[16];

    FIMEMORY *hJngMemory = NULL;
    FIMEMORY *hJpegMemory = NULL;
    FIMEMORY *hPngMemory = NULL;

    FIBITMAP *dib_rgb = NULL;
    FIBITMAP *dib_alpha = NULL;

    if(!dib || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
        return FALSE;
    }

    unsigned bpp = FreeImage_GetBPP(dib);

    switch(bpp) {
        case 8:
            if(FreeImage_GetColorType(dib) == FIC_MINISBLACK) {
                dib_rgb = dib;
                jng_color_type = MNG_COLORTYPE_JPEGGRAY;
            } else {
                // JPEG plugin will convert other types (FIC_MINISWHITE, FIC_PALETTE) to 24-bit on the fly
                //dib_rgb = FreeImage_ConvertTo24Bits(dib);
                dib_rgb = dib;
                jng_color_type = MNG_COLORTYPE_JPEGCOLOR;

            }
            break;
        case 24:
            dib_rgb = dib;
            jng_color_type = MNG_COLORTYPE_JPEGCOLOR;
            break;
        case 32:
            dib_rgb = FreeImage_ConvertTo24Bits(dib);
            jng_color_type = MNG_COLORTYPE_JPEGCOLORA;
            jng_alpha_sample_depth = 8;
            break;
        default:
            return FALSE;
    }

    jng_width = (DWORD)FreeImage_GetWidth(dib);
    jng_height = (DWORD)FreeImage_GetHeight(dib);

    try {
        hJngMemory = FreeImage_OpenMemory();

        // --- write JNG file signature ---
        FreeImage_WriteMemory(g_jng_signature, 1, 8, hJngMemory);

        // --- write a JHDR chunk ---
        SwapLong(&jng_width);
        SwapLong(&jng_height);
        memcpy(&buffer[0], &jng_width, 4);
        memcpy(&buffer[4], &jng_height, 4);
        SwapLong(&jng_width);
        SwapLong(&jng_height);
        buffer[8] = jng_color_type;
        buffer[9] = jng_image_sample_depth;
        buffer[10] = jng_image_compression_method;
        buffer[11] = jng_image_interlace_method;
        buffer[12] = jng_alpha_sample_depth;
        buffer[13] = jng_alpha_compression_method;
        buffer[14] = jng_alpha_filter_method;
        buffer[15] = jng_alpha_interlace_method;
        mng_WriteChunk(mng_JHDR, &buffer[0], 16, hJngMemory);

        // --- write a sequence of JDAT chunks ---
        hJpegMemory = FreeImage_OpenMemory();
        flags |= JPEG_BASELINE;
        if(!FreeImage_SaveToMemory(FIF_JPEG, dib_rgb, hJpegMemory, flags)) {
            throw (const char*)NULL;
        }
        if(dib_rgb != dib) {
            FreeImage_Unload(dib_rgb);
            dib_rgb = NULL;
        }
        {
            BYTE *jpeg_data = NULL;
            DWORD size_in_bytes = 0;

            // get a pointer to the stream buffer
            FreeImage_AcquireMemory(hJpegMemory, &jpeg_data, &size_in_bytes);
            // write chunks
            for(DWORD k = 0; k < size_in_bytes;) {
                DWORD bytes_left = size_in_bytes - k;
                DWORD chunk_size = MIN(JPEG_CHUNK_SIZE, bytes_left);
                mng_WriteChunk(mng_JDAT, &jpeg_data[k], chunk_size, hJngMemory);
                k += chunk_size;
            }
        }
        FreeImage_CloseMemory(hJpegMemory);
        hJpegMemory = NULL;

        // --- write alpha layer as a sequence of IDAT chunk ---
        if((bpp == 32) && (jng_color_type == MNG_COLORTYPE_JPEGCOLORA)) {
            dib_alpha = FreeImage_GetChannel(dib, FICC_ALPHA);

            hPngMemory = FreeImage_OpenMemory();
            if(!FreeImage_SaveToMemory(FIF_PNG, dib_alpha, hPngMemory, PNG_DEFAULT)) {
                throw (const char*)NULL;
            }
            FreeImage_Unload(dib_alpha);
            dib_alpha = NULL;
            // get the IDAT chunk
            {
                BOOL bResult = FALSE;
                DWORD start_pos = 0;
                DWORD next_pos = 0;
                long offset = 8;

                do {
                    // find the next IDAT chunk from 'offset' position
                    bResult = mng_FindChunk(hPngMemory, mng_IDAT, offset, &start_pos, &next_pos);
                    if(!bResult) break;

                    BYTE *png_data = NULL;
                    DWORD size_in_bytes = 0;

                    // get a pointer to the stream buffer
                    FreeImage_AcquireMemory(hPngMemory, &png_data, &size_in_bytes);
                    // write the IDAT chunk
                    mng_WriteChunk(mng_IDAT, &png_data[start_pos+8], next_pos - start_pos - 12, hJngMemory);

                    offset = next_pos;

                } while(bResult);
            }

            FreeImage_CloseMemory(hPngMemory);
            hPngMemory = NULL;
        }

        // --- write a IEND chunk ---
        mng_WriteChunk(mng_IEND, NULL, 0, hJngMemory);

        // write the JNG on output stream
        {
            BYTE *jng_data = NULL;
            DWORD size_in_bytes = 0;
            FreeImage_AcquireMemory(hJngMemory, &jng_data, &size_in_bytes);
            io->write_proc(jng_data, 1, size_in_bytes, handle);
        }

        FreeImage_CloseMemory(hJngMemory);
        FreeImage_CloseMemory(hJpegMemory);
        FreeImage_CloseMemory(hPngMemory);

        return TRUE;

    } catch(const char *text) {
        FreeImage_CloseMemory(hJngMemory);
        FreeImage_CloseMemory(hJpegMemory);
        FreeImage_CloseMemory(hPngMemory);
        if(dib_rgb && (dib_rgb != dib)) {
            FreeImage_Unload(dib_rgb);
        }
        FreeImage_Unload(dib_alpha);
        if(text) {
            FreeImage_OutputMessageProc(format_id, text);
        }
        return FALSE;
    }
}
Ejemplo n.º 9
0
/**
Write a metadata model as a TIF IFD to a FIMEMORY handle.
The entries in the TIF IFD are sorted in ascending order by tag id.	
The last entry is written as 0 (4 bytes) which means no more IFD to follow. 
Supported metadata models are
<ul>
<li>FIMD_EXIF_MAIN
<li>FIMD_EXIF_EXIF
<li>FIMD_EXIF_GPS
<li>FIMD_EXIF_INTEROP
</ul>
The end of the buffer is filled with 4 bytes equal to 0 (end of IFD offset)

@param dib Input FIBITMAP
@param md_model Metadata model to write
@param hmem Memory handle
@return Returns TRUE if successful, FALSE otherwise
@see tiff_get_ifd_profile
*/
static BOOL
tiff_write_ifd(FIBITMAP *dib, FREE_IMAGE_MDMODEL md_model, FIMEMORY *hmem) {
	FITAG *tag = NULL;
	FIMETADATA *mdhandle = NULL;
	std::vector<FITAG*> vTagList;
	TagLib::MDMODEL internal_md_model;

	DWORD ifd_offset = 0;	// WORD-aligned IFD value offset

	const BYTE empty_byte = 0;

	// start of the file
	const long start_of_file = FreeImage_TellMemory(hmem);

	// get the metadata count
	unsigned metadata_count = FreeImage_GetMetadataCount(md_model, dib);
	if(metadata_count == 0) {
		return FALSE;
	}

	TagLib& s = TagLib::instance();

	// check for supported metadata models
	switch(md_model) {
		case FIMD_EXIF_MAIN:
			internal_md_model = TagLib::EXIF_MAIN;
			break;
		case FIMD_EXIF_EXIF:
			internal_md_model = TagLib::EXIF_EXIF;
			break;
		case FIMD_EXIF_GPS:
			internal_md_model = TagLib::EXIF_GPS;
			break;
		case FIMD_EXIF_INTEROP:
			internal_md_model = TagLib::EXIF_INTEROP;
			break;
		default:
			return FALSE;
	}

	try {
		// 1) according to the TIFF specifications, 
		// the entries in a TIF IFD must be sorted in ascending order by tag id

		// store the tags into a vector
		vTagList.reserve(metadata_count);
		mdhandle = FreeImage_FindFirstMetadata(md_model, dib, &tag);
		if(mdhandle) {
			// parse the tags and store them inside vTagList
			do {
				// rewrite the tag id using FreeImage internal database
				// (in case the tag id is wrong or missing)
				const char *key = FreeImage_GetTagKey(tag);
				int tag_id = s.getTagID(internal_md_model, key);
				if(tag_id != -1) {
					// this is a known tag, set the tag ID
					FreeImage_SetTagID(tag, (WORD)tag_id);
					// record the tag
					vTagList.push_back(tag);
				}
				// else ignore this tag
			} while(FreeImage_FindNextMetadata(mdhandle, &tag));

			FreeImage_FindCloseMetadata(mdhandle);

			// sort the vector by tag id
			std::sort(vTagList.begin(), vTagList.end(), PredicateTagIDCompare());

			// update the metadata_count
			metadata_count = (unsigned)vTagList.size();

		} else {
			throw(1);
		}

		// 2) prepare the place for each IFD entries.

		/*
		An Image File Directory (IFD) consists of a 2-byte count of the number of directory entries (i.e., the number of fields), 
		followed by a sequence of 12-byte field entries, 
		followed by a 4-byte offset of the next IFD (or 0 if none). Do not forget to write the 4 bytes of 0 after the last IFD.
		*/

		{		
			// prepare place for 2 bytes for number of entries + 12 bytes for each entry
			unsigned ifd_size = 2 + 12 * metadata_count;
			FreeImage_WriteMemory(&empty_byte, 1, ifd_size, hmem);
			// record the offset used to write values > 4-bytes
			ifd_offset = FreeImage_TellMemory(hmem);
			// rewind
			FreeImage_SeekMemory(hmem, start_of_file, SEEK_SET);
		}

		// 3) write each IFD entry in tag id ascending order

		// number of directory entries
		WORD nde = (WORD)metadata_count;
		FreeImage_WriteMemory(&nde, 1, 2, hmem);

		// for each entry ...
		for(unsigned i = 0; i < metadata_count; i++) {
			FITAG *tag = vTagList[i];
			// tag id
			WORD tag_id = FreeImage_GetTagID(tag);
			FreeImage_WriteMemory(&tag_id, 1, 2, hmem);
			// tag type (compliant with TIFF specification)
			WORD tag_type = (WORD)FreeImage_GetTagType(tag);
			FreeImage_WriteMemory(&tag_type, 1, 2, hmem);
			// tag count
			DWORD tag_count = FreeImage_GetTagCount(tag);
			FreeImage_WriteMemory(&tag_count, 1, 4, hmem);
			// tag value or offset (results are in BYTE's units)
			unsigned tag_length = FreeImage_GetTagLength(tag);
			if(tag_length <= 4) {
				// 4 bytes or less, write the value (left justified)
				const BYTE *tag_value = (BYTE*)FreeImage_GetTagValue(tag);
				FreeImage_WriteMemory(tag_value, 1, tag_length, hmem);
				for(unsigned k = tag_length; k < 4; k++) {
					FreeImage_WriteMemory(&empty_byte, 1, 1, hmem);
				}
			} else {
				// write an offset
				FreeImage_WriteMemory(&ifd_offset, 1, 4, hmem);
				// write the value
				long current_position = FreeImage_TellMemory(hmem);
				FreeImage_SeekMemory(hmem, ifd_offset, SEEK_SET);
				FreeImage_WriteMemory(FreeImage_GetTagValue(tag), 1, tag_length, hmem);
				if(tag_length & 1) {
					// align to the next WORD boundary
					FreeImage_WriteMemory(&empty_byte, 1, 1, hmem);
				}
				// next offset to use
				ifd_offset = FreeImage_TellMemory(hmem);
				// rewind
				FreeImage_SeekMemory(hmem, current_position, SEEK_SET);
			}
		}

		// end-of-IFD or next IFD (0 == none)
		FreeImage_SeekMemory(hmem, ifd_offset, SEEK_SET);
		FreeImage_WriteMemory(&empty_byte, 1, 4, hmem);

		return TRUE;
	}
	catch(int) {
		return FALSE;
	}
}
Ejemplo n.º 10
0
static int
copyFaxFile(FreeImageIO *io, fi_handle handle, TIFF* tifin, uint32 xsize, int stretch, FIMEMORY *memory) {
    BYTE *rowbuf = NULL;
    BYTE *refbuf = NULL;
    uint32 row;
    uint16 badrun;
    uint16  badfaxrun;
    uint32  badfaxlines;
    int ok;

    try {

        uint32 linesize = TIFFhowmany8(xsize);
        rowbuf = (BYTE*) _TIFFmalloc(linesize);
        refbuf = (BYTE*) _TIFFmalloc(linesize);
        if (rowbuf == NULL || refbuf == NULL) {
            throw FI_MSG_ERROR_MEMORY;
        }

        tifin->tif_rawdatasize = G3GetFileSize(io, handle);
        tifin->tif_rawdata = (tidata_t) _TIFFmalloc(tifin->tif_rawdatasize);
        if (tifin->tif_rawdata == NULL) {
            throw FI_MSG_ERROR_MEMORY;
        }

        if(!G3ReadFile(io, handle, tifin->tif_rawdata, tifin->tif_rawdatasize)) {
            throw "Read error at scanline 0";
        }
        tifin->tif_rawcp = tifin->tif_rawdata;
        tifin->tif_rawcc = tifin->tif_rawdatasize;

        (*tifin->tif_setupdecode)(tifin);
        (*tifin->tif_predecode)(tifin, (uint16) 0);
        tifin->tif_row = 0;
        badfaxlines = 0;
        badfaxrun = 0;

        _TIFFmemset(refbuf, 0, linesize);
        row = 0;
        badrun = 0;     // current run of bad lines
        while (tifin->tif_rawcc > 0) {
            ok = (*tifin->tif_decoderow)(tifin, rowbuf, linesize, 0);
            if (!ok) {
                badfaxlines++;
                badrun++;
                // regenerate line from previous good line
                _TIFFmemcpy(rowbuf, refbuf, linesize);
            } else {
                if (badrun > badfaxrun)
                    badfaxrun = badrun;
                badrun = 0;
                _TIFFmemcpy(refbuf, rowbuf, linesize);
            }
            tifin->tif_row++;

            FreeImage_WriteMemory(rowbuf, linesize, 1, memory);
            row++;
            if (stretch) {
                FreeImage_WriteMemory(rowbuf, linesize, 1, memory);
                row++;
            }
        }
        if (badrun > badfaxrun)
            badfaxrun = badrun;

        _TIFFfree(tifin->tif_rawdata);
        tifin->tif_rawdata = NULL;

        _TIFFfree(rowbuf);
        _TIFFfree(refbuf);

        /*
          if (verbose) {
          fprintf(stderr, "%d rows in input\n", rows);
          fprintf(stderr, "%ld total bad rows\n", (long) badfaxlines);
          fprintf(stderr, "%d max consecutive bad rows\n", badfaxrun);
          }
        */

    } catch(const char *message) {
        if(rowbuf) _TIFFfree(rowbuf);
        if(refbuf) _TIFFfree(refbuf);
        if(tifin->tif_rawdata) {
            _TIFFfree(tifin->tif_rawdata);
            tifin->tif_rawdata = NULL;
        }
        FreeImage_OutputMessageProc(s_format_id, message);

        return -1;
    }

    return (row);
}