/// <summary> /// This method loads the image into whole_image during the first call on /// get_pixel_rows. /// </summary> private int preload_image() { cdjpeg_progress_mgr progress = cinfo.Progress as cdjpeg_progress_mgr; /* Read the data into a virtual array in input-file row order. */ for (int row = 0; row < cinfo.Image_height; row++) { if (progress != null) { progress.Pass_counter = row; progress.Pass_limit = cinfo.Image_height; progress.Updated(); } byte[][] image_ptr = whole_image.Access(row, 1); int imageIndex = 0; for (int col = row_width; col > 0; col--) { /* inline copy of read_byte() for speed */ int c = input_file.ReadByte(); if (c == -1) { cinfo.ERREXIT(J_MESSAGE_CODE.JERR_INPUT_EOF); } image_ptr[0][imageIndex] = (byte)c; imageIndex++; } } if (progress != null) { progress.completed_extra_passes++; } /* Set up to read from the virtual array in top-to-bottom order */ switch (bits_per_pixel) { case 8: m_pixelRowsMethod = PixelRowsMethod.use8bit; break; case 24: m_pixelRowsMethod = PixelRowsMethod.use24bit; break; case 32: m_pixelRowsMethod = PixelRowsMethod.use32bit; break; default: cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADDEPTH); break; } source_row = cinfo.Image_height; /* And read the first row */ return(get_pixel_rows()); }
/// <summary> /// Read the file header; detects image size and component count. /// </summary> public override void start_input() { byte[] bmpfileheader = new byte[14]; /* Read and verify the bitmap file header */ if (!ReadOK(input_file, bmpfileheader, 0, 14)) cinfo.ERREXIT(J_MESSAGE_CODE.JERR_INPUT_EOF); if (GET_2B(bmpfileheader, 0) != 0x4D42) /* 'BM' */ cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_NOT); int bfOffBits = GET_4B(bmpfileheader, 10); /* We ignore the remaining fileheader fields */ /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows), * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which. */ byte[] bmpinfoheader = new byte[64]; if (!ReadOK(input_file, bmpinfoheader, 0, 4)) cinfo.ERREXIT(J_MESSAGE_CODE.JERR_INPUT_EOF); int headerSize = GET_4B(bmpinfoheader, 0); if (headerSize < 12 || headerSize> 64) cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADHEADER); if (!ReadOK(input_file, bmpinfoheader, 4, headerSize - 4)) cinfo.ERREXIT(J_MESSAGE_CODE.JERR_INPUT_EOF); int biWidth = 0; /* initialize to avoid compiler warning */ int biHeight = 0; int biPlanes; int biCompression; int biXPelsPerMeter; int biYPelsPerMeter; int biClrUsed = 0; int mapentrysize = 0; /* 0 indicates no colormap */ switch (headerSize) { case 12: /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */ biWidth = GET_2B(bmpinfoheader, 4); biHeight = GET_2B(bmpinfoheader, 6); biPlanes = GET_2B(bmpinfoheader, 8); bits_per_pixel = GET_2B(bmpinfoheader, 10); switch (bits_per_pixel) { case 8: /* colormapped image */ mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */ cinfo.TRACEMS(1, (int)ADDON_MESSAGE_CODE.JTRC_BMP_OS2_MAPPED, biWidth, biHeight); break; case 24: /* RGB image */ cinfo.TRACEMS(1, (int)ADDON_MESSAGE_CODE.JTRC_BMP_OS2, biWidth, biHeight); break; default: cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADDEPTH); break; } if (biPlanes != 1) cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADPLANES); break; case 40: case 64: /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */ /* or OS/2 2.x header, which has additional fields that we ignore */ biWidth = GET_4B(bmpinfoheader, 4); biHeight = GET_4B(bmpinfoheader, 8); biPlanes = GET_2B(bmpinfoheader, 12); bits_per_pixel = GET_2B(bmpinfoheader, 14); biCompression = GET_4B(bmpinfoheader, 16); biXPelsPerMeter = GET_4B(bmpinfoheader, 24); biYPelsPerMeter = GET_4B(bmpinfoheader, 28); biClrUsed = GET_4B(bmpinfoheader, 32); /* biSizeImage, biClrImportant fields are ignored */ switch (bits_per_pixel) { case 8: /* colormapped image */ mapentrysize = 4; /* Windows uses RGBQUAD colormap */ cinfo.TRACEMS(1, (int)ADDON_MESSAGE_CODE.JTRC_BMP_MAPPED, biWidth, biHeight); break; case 24: /* RGB image */ cinfo.TRACEMS(1, (int)ADDON_MESSAGE_CODE.JTRC_BMP, biWidth, biHeight); break; default: cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADDEPTH); break; } if (biPlanes != 1) cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADPLANES); if (biCompression != 0) cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_COMPRESSED); if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) { /* Set JFIF density parameters from the BMP data */ cinfo.X_density = (short)(biXPelsPerMeter / 100); /* 100 cm per meter */ cinfo.Y_density = (short)(biYPelsPerMeter / 100); cinfo.Density_unit = DensityUnit.DotsCm; } break; default: cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADHEADER); break; } /* Compute distance to bitmap data --- will adjust for colormap below */ int bPad = bfOffBits - (headerSize + 14); /* Read the colormap, if any */ if (mapentrysize > 0) { if (biClrUsed <= 0) biClrUsed = 256; /* assume it's 256 */ else if (biClrUsed > 256) cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADCMAP); /* Allocate space to store the colormap */ colormap = jpeg_common_struct.AllocJpegSamples(biClrUsed, 3); /* and read it from the file */ read_colormap(biClrUsed, mapentrysize); /* account for size of colormap */ bPad -= biClrUsed * mapentrysize; } /* Skip any remaining pad bytes */ if (bPad < 0) /* incorrect bfOffBits value? */ cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADHEADER); while (--bPad >= 0) read_byte(); /* Compute row width in file, including padding to 4-byte boundary */ if (bits_per_pixel == 24) row_width = biWidth * 3; else row_width = biWidth; while ((row_width & 3) != 0) row_width++; /* Allocate space for inversion array, prepare for preload pass */ whole_image = jpeg_common_struct.CreateSamplesArray(row_width, biHeight); whole_image.ErrorProcessor = cinfo; m_pixelRowsMethod = PixelRowsMethod.preload; if (cinfo.Progress != null) { cdjpeg_progress_mgr progress = cinfo.Progress as cdjpeg_progress_mgr; if (progress != null) { /* count file input as separate pass */ progress.total_extra_passes++; } } /* Allocate one-row buffer for returned data */ buffer = jpeg_common_struct.AllocJpegSamples(biWidth * 3, 1); buffer_height = 1; cinfo.In_color_space = J_COLOR_SPACE.JCS_RGB; cinfo.Input_components = 3; cinfo.Data_precision = 8; cinfo.Image_width = biWidth; cinfo.Image_height = biHeight; }
/// <summary> /// This method loads the image into whole_image during the first call on /// get_pixel_rows. /// </summary> private int preload_image() { cdjpeg_progress_mgr progress = cinfo.Progress as cdjpeg_progress_mgr; /* Read the data into a virtual array in input-file row order. */ for (int row = 0; row < cinfo.Image_height; row++) { if (progress != null) { progress.Pass_counter = row; progress.Pass_limit = cinfo.Image_height; progress.Updated(); } byte[][] image_ptr = whole_image.Access(row, 1); int imageIndex = 0; for (int col = row_width; col > 0; col--) { /* inline copy of read_byte() for speed */ int c = input_file.ReadByte(); if (c == -1) cinfo.ERREXIT(J_MESSAGE_CODE.JERR_INPUT_EOF); image_ptr[0][imageIndex] = (byte)c; imageIndex++; } } if (progress != null) progress.completed_extra_passes++; /* Set up to read from the virtual array in top-to-bottom order */ switch (bits_per_pixel) { case 8: m_pixelRowsMethod = PixelRowsMethod.use8bit; break; case 24: m_pixelRowsMethod = PixelRowsMethod.use24bit; break; default: cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADDEPTH); break; } source_row = cinfo.Image_height; /* And read the first row */ return get_pixel_rows(); }
/// <summary> /// Read the file header; detects image size and component count. /// </summary> public override void start_input() { byte[] bmpfileheader = new byte[14]; /* Read and verify the bitmap file header */ if (!ReadOK(input_file, bmpfileheader, 0, 14)) { cinfo.ERREXIT(J_MESSAGE_CODE.JERR_INPUT_EOF); } if (GET_2B(bmpfileheader, 0) != 0x4D42) /* 'BM' */ { cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_NOT); } int bfOffBits = GET_4B(bmpfileheader, 10); /* We ignore the remaining fileheader fields */ /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows), * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which. */ byte[] bmpinfoheader = new byte[64]; if (!ReadOK(input_file, bmpinfoheader, 0, 4)) { cinfo.ERREXIT(J_MESSAGE_CODE.JERR_INPUT_EOF); } int headerSize = GET_4B(bmpinfoheader, 0); if (headerSize < 12 || headerSize > 64) { cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADHEADER); } if (!ReadOK(input_file, bmpinfoheader, 4, headerSize - 4)) { cinfo.ERREXIT(J_MESSAGE_CODE.JERR_INPUT_EOF); } int biWidth = 0; /* initialize to avoid compiler warning */ int biHeight = 0; int biPlanes = 0; int biCompression; int biXPelsPerMeter; int biYPelsPerMeter; int biClrUsed = 0; int mapentrysize = 0; /* 0 indicates no colormap */ switch (headerSize) { case 12: /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */ biWidth = GET_2B(bmpinfoheader, 4); biHeight = GET_2B(bmpinfoheader, 6); biPlanes = GET_2B(bmpinfoheader, 8); bits_per_pixel = GET_2B(bmpinfoheader, 10); switch (bits_per_pixel) { case 8: /* colormapped image */ mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */ cinfo.TRACEMS(1, (int)ADDON_MESSAGE_CODE.JTRC_BMP_OS2_MAPPED, biWidth, biHeight); break; case 24: /* RGB image */ cinfo.TRACEMS(1, (int)ADDON_MESSAGE_CODE.JTRC_BMP_OS2, biWidth, biHeight); break; default: cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADDEPTH); break; } break; case 40: case 64: /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */ /* or OS/2 2.x header, which has additional fields that we ignore */ biWidth = GET_4B(bmpinfoheader, 4); biHeight = GET_4B(bmpinfoheader, 8); biPlanes = GET_2B(bmpinfoheader, 12); bits_per_pixel = GET_2B(bmpinfoheader, 14); biCompression = GET_4B(bmpinfoheader, 16); biXPelsPerMeter = GET_4B(bmpinfoheader, 24); biYPelsPerMeter = GET_4B(bmpinfoheader, 28); biClrUsed = GET_4B(bmpinfoheader, 32); /* biSizeImage, biClrImportant fields are ignored */ switch (bits_per_pixel) { case 8: /* colormapped image */ mapentrysize = 4; /* Windows uses RGBQUAD colormap */ cinfo.TRACEMS(1, (int)ADDON_MESSAGE_CODE.JTRC_BMP_MAPPED, biWidth, biHeight); break; case 24: /* RGB image */ cinfo.TRACEMS(1, (int)ADDON_MESSAGE_CODE.JTRC_BMP, biWidth, biHeight); break; case 32: /* RGB image + Alpha channel */ cinfo.TRACEMS(1, (int)ADDON_MESSAGE_CODE.JTRC_BMP, biWidth, biHeight); break; default: cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADDEPTH); break; } if (biCompression != 0) { cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_COMPRESSED); } if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) { /* Set JFIF density parameters from the BMP data */ cinfo.X_density = (short)(biXPelsPerMeter / 100); /* 100 cm per meter */ cinfo.Y_density = (short)(biYPelsPerMeter / 100); cinfo.Density_unit = DensityUnit.DotsCm; } break; default: cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADHEADER); break; } if (biWidth <= 0 || biHeight <= 0) { cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_EMPTY); } if (biPlanes != 1) { cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADPLANES); } /* Compute distance to bitmap data --- will adjust for colormap below */ int bPad = bfOffBits - (headerSize + 14); /* Read the colormap, if any */ if (mapentrysize > 0) { if (biClrUsed <= 0) { biClrUsed = 256; /* assume it's 256 */ } else if (biClrUsed > 256) { cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADCMAP); } /* Allocate space to store the colormap */ colormap = jpeg_common_struct.AllocJpegSamples(biClrUsed, 3); /* and read it from the file */ read_colormap(biClrUsed, mapentrysize); /* account for size of colormap */ bPad -= biClrUsed * mapentrysize; } /* Skip any remaining pad bytes */ if (bPad < 0) /* incorrect bfOffBits value? */ { cinfo.ERREXIT((int)ADDON_MESSAGE_CODE.JERR_BMP_BADHEADER); } while (--bPad >= 0) { read_byte(); } /* Compute row width in file, including padding to 4-byte boundary */ if (bits_per_pixel == 24) { row_width = biWidth * 3; } else if (bits_per_pixel == 32) { row_width = biWidth * 4; } else { row_width = biWidth; } while ((row_width & 3) != 0) { row_width++; } /* Allocate space for inversion array, prepare for preload pass */ whole_image = jpeg_common_struct.CreateSamplesArray(row_width, biHeight); whole_image.ErrorProcessor = cinfo; m_pixelRowsMethod = PixelRowsMethod.preload; if (cinfo.Progress != null) { cdjpeg_progress_mgr progress = cinfo.Progress as cdjpeg_progress_mgr; if (progress != null) { /* count file input as separate pass */ progress.total_extra_passes++; } } /* Allocate one-row buffer for returned data */ buffer = jpeg_common_struct.AllocJpegSamples(biWidth * 3, 1); buffer_height = 1; cinfo.In_color_space = J_COLOR_SPACE.JCS_RGB; cinfo.Input_components = 3; cinfo.Data_precision = 8; cinfo.Image_width = biWidth; cinfo.Image_height = biHeight; }