📄 tif_jpeg.c
字号:
return (0); } } /* Create a JPEGTables field if appropriate */ if (sp->jpegtablesmode & (JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF)) { if (!prepare_JPEGTables(tif)) return (0); /* Mark the field present */ /* Can't use TIFFSetField since BEENWRITING is already set! */ TIFFSetFieldBit(tif, FIELD_JPEGTABLES); tif->tif_flags |= TIFF_DIRTYDIRECT; } else { /* We do not support application-supplied JPEGTables, */ /* so mark the field not present */ TIFFClrFieldBit(tif, FIELD_JPEGTABLES); } /* Direct libjpeg output to libtiff's output buffer */ TIFFjpeg_data_dest(sp, tif); return (1);}/* * Set encoding state at the start of a strip or tile. */static intJPEGPreEncode(TIFF* tif, tsample_t s){ JPEGState *sp = JState(tif); TIFFDirectory *td = &tif->tif_dir; static const char module[] = "JPEGPreEncode"; uint32 segment_width, segment_height; int downsampled_input; assert(sp != NULL); assert(!sp->cinfo.comm.is_decompressor); /* * Set encoding parameters for this strip/tile. */ if (isTiled(tif)) { segment_width = td->td_tilewidth; segment_height = td->td_tilelength; sp->bytesperline = TIFFTileRowSize(tif); } else { segment_width = td->td_imagewidth; segment_height = td->td_imagelength - tif->tif_row; if (segment_height > td->td_rowsperstrip) segment_height = td->td_rowsperstrip; sp->bytesperline = TIFFScanlineSize(tif); } if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { /* for PC 2, scale down the strip/tile size * to match a downsampled component */ segment_width = TIFFhowmany(segment_width, sp->h_sampling); segment_height = TIFFhowmany(segment_height, sp->v_sampling); } if (segment_width > 65535 || segment_height > 65535) { TIFFError(module, "Strip/tile too large for JPEG"); return (0); } sp->cinfo.c.image_width = segment_width; sp->cinfo.c.image_height = segment_height; downsampled_input = FALSE; if (td->td_planarconfig == PLANARCONFIG_CONTIG) { sp->cinfo.c.input_components = td->td_samplesperpixel; if (sp->photometric == PHOTOMETRIC_YCBCR) { if (sp->jpegcolormode == JPEGCOLORMODE_RGB) { sp->cinfo.c.in_color_space = JCS_RGB; } else { sp->cinfo.c.in_color_space = JCS_YCbCr; if (sp->h_sampling != 1 || sp->v_sampling != 1) downsampled_input = TRUE; } if (!TIFFjpeg_set_colorspace(sp, JCS_YCbCr)) return (0); /* * Set Y sampling factors; * we assume jpeg_set_colorspace() set the rest to 1 */ sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling; sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling; } else { sp->cinfo.c.in_color_space = JCS_UNKNOWN; if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) return (0); /* jpeg_set_colorspace set all sampling factors to 1 */ } } else { sp->cinfo.c.input_components = 1; sp->cinfo.c.in_color_space = JCS_UNKNOWN; if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) return (0); sp->cinfo.c.comp_info[0].component_id = s; /* jpeg_set_colorspace() set sampling factors to 1 */ if (sp->photometric == PHOTOMETRIC_YCBCR && s > 0) { sp->cinfo.c.comp_info[0].quant_tbl_no = 1; sp->cinfo.c.comp_info[0].dc_tbl_no = 1; sp->cinfo.c.comp_info[0].ac_tbl_no = 1; } } /* ensure libjpeg won't write any extraneous markers */ sp->cinfo.c.write_JFIF_header = FALSE; sp->cinfo.c.write_Adobe_marker = FALSE; /* set up table handling correctly */ if (! (sp->jpegtablesmode & JPEGTABLESMODE_QUANT)) { if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) return (0); unsuppress_quant_table(sp, 0); unsuppress_quant_table(sp, 1); } if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) sp->cinfo.c.optimize_coding = FALSE; else sp->cinfo.c.optimize_coding = TRUE; if (downsampled_input) { /* Need to use raw-data interface to libjpeg */ sp->cinfo.c.raw_data_in = TRUE; tif->tif_encoderow = JPEGEncodeRaw; tif->tif_encodestrip = JPEGEncodeRaw; tif->tif_encodetile = JPEGEncodeRaw; } else { /* Use normal interface to libjpeg */ sp->cinfo.c.raw_data_in = FALSE; tif->tif_encoderow = JPEGEncode; tif->tif_encodestrip = JPEGEncode; tif->tif_encodetile = JPEGEncode; } /* Start JPEG compressor */ if (!TIFFjpeg_start_compress(sp, FALSE)) return (0); /* Allocate downsampled-data buffers if needed */ if (downsampled_input) { if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info, sp->cinfo.c.num_components)) return (0); } sp->scancount = 0; return (1);}/* * Encode a chunk of pixels. * "Standard" case: incoming data is not downsampled. */static intJPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s){ JPEGState *sp = JState(tif); tsize_t nrows; JSAMPROW bufptr[1]; (void) s; assert(sp != NULL); /* data is expected to be supplied in multiples of a scanline */ nrows = cc / sp->bytesperline; if (cc % sp->bytesperline) TIFFWarning(tif->tif_name, "fractional scanline discarded"); while (nrows-- > 0) { bufptr[0] = (JSAMPROW) buf; if (TIFFjpeg_write_scanlines(sp, bufptr, 1) != 1) return (0); if (nrows > 0) tif->tif_row++; buf += sp->bytesperline; } return (1);}/* * Encode a chunk of pixels. * Incoming data is expected to be downsampled per sampling factors. */static intJPEGEncodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s){ JPEGState *sp = JState(tif); JSAMPLE* inptr; JSAMPLE* outptr; tsize_t nrows; JDIMENSION clumps_per_line, nclump; int clumpoffset, ci, xpos, ypos; jpeg_component_info* compptr; int samples_per_clump = sp->samplesperclump; (void) s; assert(sp != NULL); /* data is expected to be supplied in multiples of a scanline */ nrows = cc / sp->bytesperline; if (cc % sp->bytesperline) TIFFWarning(tif->tif_name, "fractional scanline discarded"); /* Cb,Cr both have sampling factors 1, so this is correct */ clumps_per_line = sp->cinfo.c.comp_info[1].downsampled_width; while (nrows-- > 0) { /* * Fastest way to separate the data is to make one pass * over the scanline for each row of each component. */ clumpoffset = 0; /* first sample in clump */ for (ci = 0, compptr = sp->cinfo.c.comp_info; ci < sp->cinfo.c.num_components; ci++, compptr++) { int hsamp = compptr->h_samp_factor; int vsamp = compptr->v_samp_factor; int padding = (int) (compptr->width_in_blocks * DCTSIZE - clumps_per_line * hsamp); for (ypos = 0; ypos < vsamp; ypos++) { inptr = ((JSAMPLE*) buf) + clumpoffset; outptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; if (hsamp == 1) { /* fast path for at least Cb and Cr */ for (nclump = clumps_per_line; nclump-- > 0; ) { *outptr++ = inptr[0]; inptr += samples_per_clump; } } else { /* general case */ for (nclump = clumps_per_line; nclump-- > 0; ) { for (xpos = 0; xpos < hsamp; xpos++) *outptr++ = inptr[xpos]; inptr += samples_per_clump; } } /* pad each scanline as needed */ for (xpos = 0; xpos < padding; xpos++) { *outptr = outptr[-1]; outptr++; } clumpoffset += hsamp; } } sp->scancount++; if (sp->scancount >= DCTSIZE) { int n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) return (0); sp->scancount = 0; } if (nrows > 0) tif->tif_row++; buf += sp->bytesperline; } return (1);}/* * Finish up at the end of a strip or tile. */static intJPEGPostEncode(TIFF* tif){ JPEGState *sp = JState(tif); if (sp->scancount > 0) { /* * Need to emit a partial bufferload of downsampled data. * Pad the data vertically. */ int ci, ypos, n; jpeg_component_info* compptr; for (ci = 0, compptr = sp->cinfo.c.comp_info; ci < sp->cinfo.c.num_components; ci++, compptr++) { int vsamp = compptr->v_samp_factor; tsize_t row_width = compptr->width_in_blocks * DCTSIZE * sizeof(JSAMPLE); for (ypos = sp->scancount * vsamp; ypos < DCTSIZE * vsamp; ypos++) { _TIFFmemcpy((tdata_t)sp->ds_buffer[ci][ypos], (tdata_t)sp->ds_buffer[ci][ypos-1], row_width); } } n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) return (0); } return (TIFFjpeg_finish_compress(JState(tif)));}static voidJPEGCleanup(TIFF* tif){ if (tif->tif_data) { JPEGState *sp = JState(tif); TIFFjpeg_destroy(sp); /* release libjpeg resources */ if (sp->jpegtables) /* tag value */ _TIFFfree(sp->jpegtables); _TIFFfree(tif->tif_data); /* release local state */ tif->tif_data = NULL; }}static intJPEGVSetField(TIFF* tif, ttag_t tag, va_list ap){ JPEGState* sp = JState(tif); TIFFDirectory* td = &tif->tif_dir; uint32 v32; switch (tag) { case TIFFTAG_JPEGTABLES: v32 = va_arg(ap, uint32); if (v32 == 0) { /* XXX */ return (0); } _TIFFsetByteArray(&sp->jpegtables, va_arg(ap, void*), (long) v32); sp->jpegtables_length = v32; TIFFSetFieldBit(tif, FIELD_JPEGTABLES); break; case TIFFTAG_JPEGQUALITY: sp->jpegquality = va_arg(ap, int); return (1); /* pseudo tag */ case TIFFTAG_JPEGCOLORMODE: sp->jpegcolormode = va_arg(ap, int); /* * Mark whether returned data is up-sampled or not * so TIFFStripSize and TIFFTileSize return values * that reflect the true amount of data. */ tif->tif_flags &= ~TIFF_UPSAMPLED; if (td->td_planarconfig == PLANARCONFIG_CONTIG) { if (td->td_photometric == PHOTOMETRIC_YCBCR && sp->jpegcolormode == JPEGCOLORMODE_RGB) { tif->tif_flags |= TIFF_UPSAMPLED; } else { if (td->td_ycbcrsubsampling[0] != 1 || td->td_ycbcrsubsampling[1] != 1) ; /* XXX what about up-sampling? */ } } /* * Must recalculate cached tile size * in case sampling state changed. */ tif->tif_tilesize = TIFFTileSize(tif); return (1); /* pseudo tag */ case TIFFTAG_JPEGTABLESMODE: sp->jpegtablesmode = va_arg(ap, int); return (1); /* pseudo tag */ default: return (*sp->vsetparent)(tif, tag, ap); } tif->tif_flags |= TIFF_DIRTYDIRECT; return (1);}static intJPEGVGetField(TIFF* tif, ttag_t tag, va_list ap){ JPEGState* sp = JState(tif); switch (tag) { case TIFFTAG_JPEGTABLES: /* u_short is bogus --- should be uint32 ??? */ /* TIFFWriteNormalTag needs fixed XXX */ *va_arg(ap, u_short*) = (u_short) sp->jpegtables_length; *va_arg(ap, void**) = sp->jpegtables; break; case TIFFTAG_JPEGQUALITY: *va_arg(ap, int*) = sp->jpegquality; break; case TIFFTAG_JPEGCOLORMODE: *va_arg(ap, int*) = sp->jpegcolormode; break; case TIFFTAG_JPEGTABLESMODE: *va_arg(ap, int*) = sp->jpegtablesmode; break; default: return (*sp->vgetparent)(tif, tag, ap); } return (1);}static voidJPEGPrintDir(TIFF* tif, FILE* fd, long flags){ JPEGState* sp = JState(tif); (void) flags; if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) fprintf(fd, " JPEG Tables: (%lu bytes)\n", (u_long) sp->jpegtables_length);}static uint32JPEGDefaultStripSize(TIFF* tif, uint32 s){ JPEGState* sp = JState(tif); TIFFDirectory *td = &tif->tif_dir; s = (*sp->defsparent)(tif, s); if (s < td->td_imagelength) s = TIFFroundup(s, td->td_ycbcrsubsampling[1] * DCTSIZE); return (s);}static voidJPEGDefaultTileSize(TIFF* tif, uint32* tw, uint32* th){ JPEGState* sp = JState(tif); TIFFDirectory *td = &tif->tif_dir; (*sp->deftparent)(tif, tw, th); *tw = TIFFroundup(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE); *th = TIFFroundup(*th, td->td_ycbcrsubsampling[1] * DCTSIZE);}intTIFFInitJPEG(TIFF* tif, int scheme){ JPEGState* sp; assert(scheme == COMPRESSION_JPEG); /* * Allocate state block so tag methods have storage to record values. */ tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (JPEGState)); if (tif->tif_data == NULL) { TIFFError("TIFFInitJPEG", "No space for JPEG state block"); return (0); } sp = JState(tif); sp->tif = tif; /* back link */ /* * Merge codec-specific tag information and * override parent get/set field methods. */ _TIFFMergeFieldInfo(tif, jpegFieldInfo, N(jpegFieldInfo)); sp->vgetparent = tif->tif_vgetfield; tif->tif_vgetfield = JPEGVGetField; /* hook for codec tags */ sp->vsetparent = tif->tif_vsetfield; tif->tif_vsetfield = JPEGVSetField; /* hook for codec tags */ tif->tif_printdir = JPEGPrintDir; /* hook for codec tags */ /* Default values for codec-specific fields */ sp->jpegtables = NULL; sp->jpegtables_length = 0; sp->jpegquality = 75; /* Default IJG quality */ sp->jpegcolormode = JPEGCOLORMODE_RAW; sp->jpegtablesmode = JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF; /* * Install codec methods. */ tif->tif_setupdecode = JPEGSetupDecode; tif->tif_predecode = JPEGPreDecode; tif->tif_decoderow = JPEGDecode; tif->tif_decodestrip = JPEGDecode; tif->tif_decodetile = JPEGDecode; tif->tif_setupencode = JPEGSetupEncode; tif->tif_preencode = JPEGPreEncode; tif->tif_postencode = JPEGPostEncode; tif->tif_encoderow = JPEGEncode; tif->tif_encodestrip = JPEGEncode; tif->tif_encodetile = JPEGEncode; tif->tif_cleanup = JPEGCleanup; sp->defsparent = tif->tif_defstripsize; tif->tif_defstripsize = JPEGDefaultStripSize; sp->deftparent = tif->tif_deftilesize; tif->tif_deftilesize = JPEGDefaultTileSize; tif->tif_flags |= TIFF_NOBITREV; /* no bit reversal, please */ /* * Initialize libjpeg. */ if (tif->tif_mode == O_RDONLY) { if (!TIFFjpeg_create_decompress(sp)) return (0); } else { if (!TIFFjpeg_create_compress(sp)) return (0); } return (1);}#endif /* JPEG_SUPPORT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -