📄 image_in.cpp
字号:
/*****************************************************************************/// File: image_in.cpp [scope = APPS/IMAGE-IO]// Version: Kakadu, V2.2.1// Author: David Taubman// Last Revised: 5 July, 2001/*****************************************************************************/// Copyright 2001, David Taubman, The University of New South Wales (UNSW)// The copyright owner is Unisearch Ltd, Australia (commercial arm of UNSW)// Neither this copyright statement, nor the licensing details below// may be removed from this file or dissociated from its contents./*****************************************************************************/// Licensee: Book Owner// License number: 99999// The Licensee has been granted a NON-COMMERCIAL license to the contents of// this source file, said Licensee being the owner of a copy of the book,// "JPEG2000: Image Compression Fundamentals, Standards and Practice," by// Taubman and Marcellin (Kluwer Academic Publishers, 2001). A brief summary// of the license appears below. This summary is not to be relied upon in// preference to the full text of the license agreement, which was accepted// upon breaking the seal of the compact disc accompanying the above-mentioned// book.// 1. The Licensee has the right to Non-Commercial Use of the Kakadu software,// Version 2.2, including distribution of one or more Applications built// using the software, provided such distribution is not for financial// return.// 2. The Licensee has the right to personal use of the Kakadu software,// Version 2.2.// 3. The Licensee has the right to distribute Reusable Code (including// source code and dynamically or statically linked libraries) to a Third// Party, provided the Third Party possesses a license to use the Kakadu// software, Version 2.2, and provided such distribution is not for// financial return./******************************************************************************Description: Implements image file reading for a variety of different file formats:currently BMP, PGM, PPM and RAW only. Readily extendible to include otherfile formats without affecting the rest of the system.******************************************************************************/// System includes#include <string.h>#include <math.h>#include <assert.h>// Core includes#include "kdu_messaging.h"#include "kdu_sample_processing.h"// Image includes#include "kdu_image.h"#include "image_local.h"/* ========================================================================= *//* Internal Functions *//* ========================================================================= *//*****************************************************************************//* STATIC to_little_endian *//*****************************************************************************/static void to_little_endian(kdu_int32 * words, int num_words){ kdu_int32 test = 1; kdu_byte *first_byte = (kdu_byte *) &test; if (*first_byte) return; // Machine uses little-endian architecture already. kdu_int32 tmp; for (; num_words--; words++) { tmp = *words; *words = ((tmp >> 24) & 0x000000FF) + ((tmp >> 8) & 0x0000FF00) + ((tmp << 8) & 0x00FF0000) + ((tmp << 24) & 0xFF000000); }}/*****************************************************************************//* INLINE from_little_endian *//*****************************************************************************/static inline void from_little_endian(kdu_int32 * words, int num_words){ to_little_endian(words,num_words);}/*****************************************************************************//* INLINE eat_white_and_comments *//*****************************************************************************/static inline void eat_white_and_comments(FILE *in){ int ch; bool in_comment; in_comment = false; while ((ch = getc(in)) != EOF) if (ch == '#') in_comment = true; else if (ch == '\n') in_comment = false; else if ((!in_comment) && (ch != ' ') && (ch != '\t') && (ch != '\r')) { ungetc(ch,in); return; }}/*****************************************************************************//* STATIC convert_words_to_floats *//*****************************************************************************/static void convert_words_to_floats(kdu_byte *src, kdu_sample32 *dest, int num, int precision, bool is_signed, int sample_bytes){ float scale; if (precision < 30) scale = (float)(1<<precision); else scale = ((float)(1<<30)) * ((float)(1<<(precision-30))); scale = 1.0F / scale; kdu_int32 centre = 1<<(precision-1); kdu_int32 offset = (is_signed)?centre:0; kdu_int32 mask = ~((-1)<<precision); kdu_int32 val; if (sample_bytes == 1) for (; num > 0; num--, dest++) { val = *(src++); val += offset; val &= mask; val -= centre; dest->fval = ((float) val) * scale; } else if (sample_bytes == 2) for (; num > 0; num--, dest++) { val = *(src++); val = (val<<8) + *(src++); val += offset; val &= mask; val -= centre; dest->fval = ((float) val) * scale; } else if (sample_bytes == 3) for (; num > 0; num--, dest++) { val = *(src++); val = (val<<8) + *(src++); val = (val<<8) + *(src++); val += offset; val &= mask; val -= centre; dest->fval = ((float) val) * scale; } else if (sample_bytes == 4) for (; num > 0; num--, dest++) { val = *(src++); val = (val<<8) + *(src++); val = (val<<8) + *(src++); val = (val<<8) + *(src++); val += offset; val &= mask; val -= centre; dest->fval = ((float) val) * scale; } else assert(0);}/*****************************************************************************//* STATIC convert_words_to_fixpoint *//*****************************************************************************/static void convert_words_to_fixpoint(kdu_byte *src, kdu_sample16 *dest, int num, int precision, bool is_signed, int sample_bytes){ kdu_int32 upshift = KDU_FIX_POINT-precision; if (upshift < 0) { kdu_error e; e << "Cannot use 16-bit representation with high " "bit-depth data"; } kdu_int32 centre = 1<<(precision-1); kdu_int32 offset = (is_signed)?centre:0; kdu_int32 mask = ~((-1)<<precision); kdu_int32 val; if (sample_bytes == 1) for (; num > 0; num--, dest++) { val = *(src++); val += offset; val &= mask; val -= centre; dest->ival = (kdu_int16)(val<<upshift); } else if (sample_bytes == 2) for (; num > 0; num--, dest++) { val = *(src++); val = (val<<8) + *(src++); val += offset; val &= mask; val -= centre; dest->ival = (kdu_int16)(val<<upshift); } else { kdu_error e; e << "Cannot use 16-bit representation with high " "bit-depth data"; }}/*****************************************************************************//* STATIC convert_words_to_ints *//*****************************************************************************/static void convert_words_to_ints(kdu_byte *src, kdu_sample32 *dest, int num, int precision, bool is_signed, int sample_bytes){ kdu_int32 centre = 1<<(precision-1); kdu_int32 offset = (is_signed)?centre:0; kdu_int32 mask = ~((-1)<<precision); kdu_int32 val; if (sample_bytes == 1) for (; num > 0; num--, dest++) { val = *(src++); val += offset; val &= mask; val -= centre; dest->ival = val; } else if (sample_bytes == 2) for (; num > 0; num--, dest++) { val = *(src++); val = (val<<8) + *(src++); val += offset; val &= mask; val -= centre; dest->ival = val; } else if (sample_bytes == 3) for (; num > 0; num--, dest++) { val = *(src++); val = (val<<8) + *(src++); val = (val<<8) + *(src++); val += offset; val &= mask; val -= centre; dest->ival = val; } else if (sample_bytes == 4) for (; num > 0; num--, dest++) { val = *(src++); val = (val<<8) + *(src++); val = (val<<8) + *(src++); val = (val<<8) + *(src++); val += offset; val &= mask; val -= centre; dest->ival = val; } else assert(0);}/*****************************************************************************//* STATIC convert_words_to_shorts *//*****************************************************************************/static void convert_words_to_shorts(kdu_byte *src, kdu_sample16 *dest, int num, int precision, bool is_signed, int sample_bytes){ kdu_int32 centre = 1<<(precision-1); kdu_int32 offset = (is_signed)?centre:0; kdu_int32 mask = ~((-1)<<precision); kdu_int32 val; if (sample_bytes == 1) for (; num > 0; num--, dest++) { val = *(src++); val += offset; val &= mask; val -= centre; dest->ival = (kdu_int16) val; } else if (sample_bytes == 2) for (; num > 0; num--, dest++) { val = *(src++); val = (val<<8) + *(src++); val += offset; val &= mask; val -= centre; dest->ival = (kdu_int16) val; } else { kdu_error e; e << "Cannot use 16-bit representation with high " "bit-depth data"; }}/* ========================================================================= *//* kdu_image_in *//* ========================================================================= *//*****************************************************************************//* kdu_image_in::kdu_image_in *//*****************************************************************************/kdu_image_in::kdu_image_in(char const *fname, siz_params *siz, int &next_comp_idx, bool &vflip, kdu_rgb8_palette *palette){ char const *suffix; in = NULL; vflip = false; // Allows derived constructors to ignore the argument. if ((suffix = strrchr(fname,'.')) != NULL) { if ((strcmp(suffix+1,"pbm") == 0) || (strcmp(suffix+1,"PBM") == 0)) in = new pbm_in(fname,siz,next_comp_idx,palette); else if ((strcmp(suffix+1,"pgm") == 0) || (strcmp(suffix+1,"PGM") == 0)) in = new pgm_in(fname,siz,next_comp_idx); else if ((strcmp(suffix+1,"ppm") == 0) || (strcmp(suffix+1,"PPM") == 0)) in = new ppm_in(fname,siz,next_comp_idx); else if ((strcmp(suffix+1,"bmp") == 0) || (strcmp(suffix+1,"BMP") == 0)) in = new bmp_in(fname,siz,next_comp_idx,vflip,palette); else if ((strcmp(suffix+1,"raw") == 0) || (strcmp(suffix+1,"RAW") == 0)) in = new raw_in(fname,siz,next_comp_idx); } if (in == NULL) { kdu_error e; e << "Image file, \"" << fname << ", does not have a " "recognized suffix. Valid suffices are currently: " "\"bmp\", \"pgm\", \"ppm\" and \"raw\". " "Upper or lower case may be used, but must be used consistently."; }}/* ========================================================================= *//* pbm_in *//* ========================================================================= *//*****************************************************************************//* pbm_in::pbm_in *//*****************************************************************************/pbm_in::pbm_in(char const *fname, siz_params *siz, int &next_comp_idx, kdu_rgb8_palette *palette){ char magic[3]; if ((in = fopen(fname,"rb")) == NULL) { kdu_error e; e << "Unable to open input image file, \"" << fname <<"\".";} magic[0] = magic[1] = magic[2] = '\0'; fread(magic,1,2,in); if (strcmp(magic,"P4") != 0) { kdu_error e; e << "PBM image file must start with the magic string, " "\"P4\"!"; } bool failed = false; eat_white_and_comments(in); if (fscanf(in,"%d",&cols) != 1) failed = true; eat_white_and_comments(in); if (fscanf(in,"%d",&rows) != 1) failed = true; if (failed) {kdu_error e; e << "Image file \"" << fname << "\" does not appear to " "have a valid PBM header."; } int ch; while ((ch = fgetc(in)) != EOF) if (ch == '\n') break; comp_idx = next_comp_idx++; siz->set(Sdims,comp_idx,0,rows); siz->set(Sdims,comp_idx,1,cols); siz->set(Ssigned,comp_idx,0,false); siz->set(Sprecision,comp_idx,0,1); if ((palette != NULL) && !palette->exists()) { palette->input_bits = 1; palette->output_bits = 8; palette->source_component = comp_idx; palette->blue[0] = palette->green[0] = palette->red[0] = 0; palette->blue[1] = palette->green[1] = palette->red[1] = 255; // Note that we will be flipping the bits so that a 0 really does // represent black, rather than white -- this is more efficient for // coding facsimile type images where the background is white. } incomplete_lines = free_lines = NULL; num_unread_rows = rows;}/*****************************************************************************//* pbm_in::~pbm_in *//*****************************************************************************/pbm_in::~pbm_in(){ if ((num_unread_rows > 0) || (incomplete_lines != NULL)) { kdu_warning w; w << "Not all rows of image component " << comp_idx << " were consumed!"; } image_line_buf *tmp; while ((tmp=incomplete_lines) != NULL) { incomplete_lines = tmp->next; delete tmp; } while ((tmp=free_lines) != NULL) { free_lines = tmp->next; delete tmp; } fclose(in);}/*****************************************************************************//* pbm_in::get *//*****************************************************************************/bool pbm_in::get(int comp_idx, kdu_line_buf &line, int x_tnum){ assert(comp_idx == this->comp_idx); image_line_buf *scan, *prev=NULL; kdu_byte *sp; int n; for (scan=incomplete_lines; scan != NULL; prev=scan, scan=scan->next) { assert(scan->next_x_tnum >= x_tnum); if (scan->next_x_tnum == x_tnum) break; } if (scan == NULL) { // Need to read a new image line. assert(x_tnum == 0); // Must consume line from left to right. if (num_unread_rows == 0) return false; if ((scan = free_lines) == NULL) scan = new image_line_buf(cols+7,1); free_lines = scan->next; if (prev == NULL) incomplete_lines = scan; else prev->next = scan; n = (cols+7) >> 3; if (fread(scan->buf,1,(size_t) n,in) != (size_t) n) { kdu_error e; e << "Image file for component " << comp_idx << " terminated prematurely!"; } // Expand the packed representation into whole bytes, flipping and // storing each binary digit in the LSB of a single byte. The reason // for flipping is that PBM files represent white using a 0 and // black using a 1, but the more natural and also more efficient // representation for coding unsigned data with 1-bit precision in // JPEG2000 is the opposite.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -