/*
 * See: http://msdn.microsoft.com/en-us/library/dd145119%28VS.85%29.aspx
 * This function was copied from the MSDN example.
 * It was then modified to send the BMP data rather than save to disk
 * It was then modified to conver the BMP to JPEG and send
 * Now its realy big.
 */
int bmp2jpeg(PBYTE buf, int quality, BYTE ** buf_jpeg, DWORD * buf_jpeg_size )
{

	// Convert to JPEG stuff
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;
    cjpeg_source_ptr src_mgr;
    JDIMENSION num_scanlines;


	// JPEG conversion start here..'
	// buf is a pointer to a BMP in memory.

	/* Initialize JPEG parameters.
     * Much of this may be overridden later.
     * We need to provide some value for jpeg_set_defaults() to work.
     */

	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);
    cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
    jpeg_set_defaults(&cinfo);

	src_mgr = jinit_read_bmp(&cinfo); //Returns a cjpeg_source_ptr but is really bmp_source_ptr...

	src_mgr->input_buf = buf;
	src_mgr->read_offset = 0;
    /* Read the input file header to obtain file size & colorspace. */

	start_input_bmp(&cinfo, src_mgr);

    jpeg_default_colorspace(&cinfo);

	// TODO: accept options from the command line for grayscale and quality.
	/* Go GRAYSCALE */
	//jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE);
	/* Quality */
	jpeg_set_quality(&cinfo, quality, FALSE);

	// Write the compressed JPEG to memory: bug_jpeg
	jpeg_mem_dest(&cinfo, buf_jpeg, buf_jpeg_size);

    /* Start compressor */
    jpeg_start_compress(&cinfo, TRUE);

	/* Process data */
	while (cinfo.next_scanline < cinfo.image_height) {
		num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
		(void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
	}

	/* Finish compression and release memory */
	(*src_mgr->finish_input) (&cinfo, src_mgr);
	jpeg_finish_compress(&cinfo);
	jpeg_destroy_compress(&cinfo);

    return 1;
}
/*
 * See: http://msdn.microsoft.com/en-us/library/dd145119%28VS.85%29.aspx
 * This function was copied from the MSDN example. 
 * It was then modified to send the BMP data rather than save to disk
 * It was then modified to conver the BMP to JPEG and send
 * Now its realy big. 
 */
int bmp2jpeg(HBITMAP hBmp, HDC hDC, int quality, BYTE ** buf_jpeg, DWORD * buf_jpeg_size )
{
    // data structures
    BITMAP bmp;
    PBITMAPINFO pbmi;
    WORD cClrBits;
    BITMAPFILEHEADER hdr;       // bitmap file-header 
    PBITMAPINFOHEADER pbih;     // bitmap info-header 
    LPBYTE lpBits;              // memory pointer 
    DWORD dwTotal;              // total count of bytes 
    DWORD cb;                   // incremental count of bytes 
    BYTE *hp;                   // byte pointer 
	DWORD s;
	TCHAR* buf;

	// Convert to JPEG stuff
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;
    cjpeg_source_ptr src_mgr;
    JDIMENSION num_scanlines;

    // Retrieve the bitmap's color format, width, and height. 
    if (!GetObject(hBmp, sizeof(BITMAP), (LPVOID) &bmp))
        // GetObject failed
        return 0;
    
    // Convert the color format to a count of bits. 
    cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); 
    if (cClrBits == 1) 
      cClrBits = 1; 
    else if (cClrBits <= 4) 
      cClrBits = 4; 
    else if (cClrBits <= 8) 
      cClrBits = 8; 
    else if (cClrBits <= 16) 
      cClrBits = 16; 
    else if (cClrBits <= 24) 
      cClrBits = 24; 
    else cClrBits = 32; 
    
    // Allocate memory for the BITMAPINFO structure. (This structure 
    // contains a BITMAPINFOHEADER structure and an array of RGBQUAD 
    // data structures.) 
    if (cClrBits != 24) 
        pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits)); 

    // There is no RGBQUAD array for the 24-bit-per-pixel format. 
    else
        pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER)); 
  
    // Initialize the fields in the BITMAPINFO structure. 

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    pbmi->bmiHeader.biWidth = bmp.bmWidth; 
    pbmi->bmiHeader.biHeight = bmp.bmHeight; 
    pbmi->bmiHeader.biPlanes = bmp.bmPlanes; 
    pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; 

    if (cClrBits < 24) 
        pbmi->bmiHeader.biClrUsed = (1<<cClrBits); 

    // If the bitmap is not compressed, set the BI_RGB flag. 
    pbmi->bmiHeader.biCompression = BI_RGB; 

    // Compute the number of bytes in the array of color 
    // indices and store the result in biSizeImage. 
    pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8 
        * pbmi->bmiHeader.biHeight * cClrBits; 

    // Set biClrImportant to 0, indicating that all of the 
    // device colors are important. 
    pbmi->bmiHeader.biClrImportant = 0; 
  
  
    pbih = (PBITMAPINFOHEADER) pbmi; 
    lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
    
    
    
    if (!lpBits) {
        // GlobalAlloc failed
        //printf("error: out of memory\n");
        return 0;
    }

    // Retrieve the color table (RGBQUAD array) and the bits 
    // (array of palette indices) from the DIB. 
    if (!GetDIBits(hDC, hBmp, 0, (WORD) pbih->biHeight, lpBits, pbmi, DIB_RGB_COLORS)) {
        // GetDIBits failed
        //printf("error: GetDiBits failed\n");
        return 0;
    }

    hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M" 
    // Compute the size of the entire file. 
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + 
                          pbih->biSize + pbih->biClrUsed 
                          * sizeof(RGBQUAD) + pbih->biSizeImage); 
    hdr.bfReserved1 = 0; 
    hdr.bfReserved2 = 0; 

    // Compute the offset to the array of color indices. 
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + 
        pbih->biSize + pbih->biClrUsed * sizeof (RGBQUAD); 

	s = sizeof(BITMAPFILEHEADER);
	s = s + (sizeof(BITMAPINFOHEADER)+ pbih->biClrUsed * sizeof (RGBQUAD));
    // Copy the array of color indices into the .BMP file. 
    dwTotal = cb = pbih->biSizeImage; 
    hp = lpBits; 

	s = s + ((int) cb);
	
	buf = (TCHAR *)malloc(s * sizeof(TCHAR));
	memcpy(buf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER));
	memcpy(buf+sizeof(BITMAPFILEHEADER),(LPVOID) pbih, sizeof(BITMAPINFOHEADER)+ pbih->biClrUsed * sizeof (RGBQUAD));
	memcpy(buf+sizeof(BITMAPFILEHEADER)+ (sizeof(BITMAPINFOHEADER)+ pbih->biClrUsed * sizeof (RGBQUAD)),(LPSTR) hp, (int) cb);
	// Don't send it yet. Convert it to a JPEG.
	//packet_add_tlv_raw(resp, TLV_TYPE_DEV_SCREEN, buf, s);
    

	// JPEG conversion start here..'
	// buf is a pointer to a BMP in memory.
	
	/* Initialize JPEG parameters. 
     * Much of this may be overridden later.
     * We need to provide some value for jpeg_set_defaults() to work.
     */

	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);
    cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
    jpeg_set_defaults(&cinfo);

	src_mgr = jinit_read_bmp(&cinfo); //Returns a cjpeg_source_ptr but is really bmp_source_ptr...

	src_mgr->input_buf = buf;  
	src_mgr->read_offset = 0;
    /* Read the input file header to obtain file size & colorspace. */

	start_input_bmp(&cinfo, src_mgr);

    jpeg_default_colorspace(&cinfo);
	
	// TODO: accept options from the command line for grayscale and quality. 
	/* Go GRAYSCALE */
	//jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE);
	/* Quality */
	jpeg_set_quality(&cinfo, quality, FALSE);

	// Write the compressed JPEG to memory: bug_jpeg
	jpeg_mem_dest(&cinfo, buf_jpeg, buf_jpeg_size);

    /* Start compressor */
    jpeg_start_compress(&cinfo, TRUE);

	/* Process data */
	while (cinfo.next_scanline < cinfo.image_height) {
		num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
		(void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
	}
	
	/* Finish compression and release memory */
	(*src_mgr->finish_input) (&cinfo, src_mgr);
	jpeg_finish_compress(&cinfo);
	jpeg_destroy_compress(&cinfo);

    // Free memory. 
    GlobalFree((HGLOBAL)lpBits);
	// This wasn't being free'ed before. Shouldn't you free all malloc calls? 
	free(buf); 

    return 1;
}
/*
* See: http://msdn.microsoft.com/en-us/library/dd145119%28VS.85%29.aspx
* This function was copied from the MSDN example. 
* It was then modified to send the BMP data rather than save to disk
* It was then modified to conver the BMP to JPEG and send
* Now its realy big. 
*/
int bmp2jpegtofile(PBYTE buf, int quality, const wchar_t* name) {

	// Convert to JPEG stuff
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;
	cjpeg_source_ptr src_mgr;
	JDIMENSION num_scanlines;
	errno_t err;
	FILE *stream;

	// JPEG conversion start here..'
	// buf is a pointer to a BMP in memory.

	/* Initialize JPEG parameters. 
	* Much of this may be overridden later.
	* We need to provide some value for jpeg_set_defaults() to work.
	*/

	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);
	cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
	jpeg_set_defaults(&cinfo);

	src_mgr = jinit_read_bmp(&cinfo); //Returns a cjpeg_source_ptr but is really bmp_source_ptr...

	src_mgr->input_buf = buf;  
	src_mgr->read_offset = 0;
	/* Read the input file header to obtain file size & colorspace. */

	start_input_bmp(&cinfo, src_mgr);

	jpeg_default_colorspace(&cinfo);

	// TODO: accept options from the command line for grayscale and quality. 
	/* Go GRAYSCALE */
	//jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE);
	/* Quality */
	jpeg_set_quality(&cinfo, quality, FALSE);


	// Open for read (will fail if file "crt_fopen_s.c" does not exist)
	if( (err  = _wfopen_s( &stream, name, L"wb")) != 0 ){
		printf( "The file was not opened\n" );
		return 0;
	}

	jpeg_stdio_dest(&cinfo, stream);

	/* Start compressor */
	jpeg_start_compress(&cinfo, TRUE);

	/* Process data */
	while (cinfo.next_scanline < cinfo.image_height) {
		num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
		(void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
	}

	/* Finish compression and release memory */
	(*src_mgr->finish_input) (&cinfo, src_mgr);

	jpeg_finish_compress(&cinfo);
	jpeg_destroy_compress(&cinfo);

	fclose(stream);

	return 1;
}