17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * jcmarker.c
37dd7cddfSDavid du Colombier *
4*593dc095SDavid du Colombier * Copyright (C) 1991-1998, Thomas G. Lane.
57dd7cddfSDavid du Colombier * This file is part of the Independent JPEG Group's software.
67dd7cddfSDavid du Colombier * For conditions of distribution and use, see the accompanying README file.
77dd7cddfSDavid du Colombier *
87dd7cddfSDavid du Colombier * This file contains routines to write JPEG datastream markers.
97dd7cddfSDavid du Colombier */
107dd7cddfSDavid du Colombier
117dd7cddfSDavid du Colombier #define JPEG_INTERNALS
127dd7cddfSDavid du Colombier #include "jinclude.h"
137dd7cddfSDavid du Colombier #include "jpeglib.h"
147dd7cddfSDavid du Colombier
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier typedef enum { /* JPEG marker codes */
177dd7cddfSDavid du Colombier M_SOF0 = 0xc0,
187dd7cddfSDavid du Colombier M_SOF1 = 0xc1,
197dd7cddfSDavid du Colombier M_SOF2 = 0xc2,
207dd7cddfSDavid du Colombier M_SOF3 = 0xc3,
217dd7cddfSDavid du Colombier
227dd7cddfSDavid du Colombier M_SOF5 = 0xc5,
237dd7cddfSDavid du Colombier M_SOF6 = 0xc6,
247dd7cddfSDavid du Colombier M_SOF7 = 0xc7,
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier M_JPG = 0xc8,
277dd7cddfSDavid du Colombier M_SOF9 = 0xc9,
287dd7cddfSDavid du Colombier M_SOF10 = 0xca,
297dd7cddfSDavid du Colombier M_SOF11 = 0xcb,
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier M_SOF13 = 0xcd,
327dd7cddfSDavid du Colombier M_SOF14 = 0xce,
337dd7cddfSDavid du Colombier M_SOF15 = 0xcf,
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier M_DHT = 0xc4,
367dd7cddfSDavid du Colombier
377dd7cddfSDavid du Colombier M_DAC = 0xcc,
387dd7cddfSDavid du Colombier
397dd7cddfSDavid du Colombier M_RST0 = 0xd0,
407dd7cddfSDavid du Colombier M_RST1 = 0xd1,
417dd7cddfSDavid du Colombier M_RST2 = 0xd2,
427dd7cddfSDavid du Colombier M_RST3 = 0xd3,
437dd7cddfSDavid du Colombier M_RST4 = 0xd4,
447dd7cddfSDavid du Colombier M_RST5 = 0xd5,
457dd7cddfSDavid du Colombier M_RST6 = 0xd6,
467dd7cddfSDavid du Colombier M_RST7 = 0xd7,
477dd7cddfSDavid du Colombier
487dd7cddfSDavid du Colombier M_SOI = 0xd8,
497dd7cddfSDavid du Colombier M_EOI = 0xd9,
507dd7cddfSDavid du Colombier M_SOS = 0xda,
517dd7cddfSDavid du Colombier M_DQT = 0xdb,
527dd7cddfSDavid du Colombier M_DNL = 0xdc,
537dd7cddfSDavid du Colombier M_DRI = 0xdd,
547dd7cddfSDavid du Colombier M_DHP = 0xde,
557dd7cddfSDavid du Colombier M_EXP = 0xdf,
567dd7cddfSDavid du Colombier
577dd7cddfSDavid du Colombier M_APP0 = 0xe0,
587dd7cddfSDavid du Colombier M_APP1 = 0xe1,
597dd7cddfSDavid du Colombier M_APP2 = 0xe2,
607dd7cddfSDavid du Colombier M_APP3 = 0xe3,
617dd7cddfSDavid du Colombier M_APP4 = 0xe4,
627dd7cddfSDavid du Colombier M_APP5 = 0xe5,
637dd7cddfSDavid du Colombier M_APP6 = 0xe6,
647dd7cddfSDavid du Colombier M_APP7 = 0xe7,
657dd7cddfSDavid du Colombier M_APP8 = 0xe8,
667dd7cddfSDavid du Colombier M_APP9 = 0xe9,
677dd7cddfSDavid du Colombier M_APP10 = 0xea,
687dd7cddfSDavid du Colombier M_APP11 = 0xeb,
697dd7cddfSDavid du Colombier M_APP12 = 0xec,
707dd7cddfSDavid du Colombier M_APP13 = 0xed,
717dd7cddfSDavid du Colombier M_APP14 = 0xee,
727dd7cddfSDavid du Colombier M_APP15 = 0xef,
737dd7cddfSDavid du Colombier
747dd7cddfSDavid du Colombier M_JPG0 = 0xf0,
757dd7cddfSDavid du Colombier M_JPG13 = 0xfd,
767dd7cddfSDavid du Colombier M_COM = 0xfe,
777dd7cddfSDavid du Colombier
787dd7cddfSDavid du Colombier M_TEM = 0x01,
797dd7cddfSDavid du Colombier
807dd7cddfSDavid du Colombier M_ERROR = 0x100
817dd7cddfSDavid du Colombier } JPEG_MARKER;
827dd7cddfSDavid du Colombier
837dd7cddfSDavid du Colombier
84*593dc095SDavid du Colombier /* Private state */
85*593dc095SDavid du Colombier
86*593dc095SDavid du Colombier typedef struct {
87*593dc095SDavid du Colombier struct jpeg_marker_writer pub; /* public fields */
88*593dc095SDavid du Colombier
89*593dc095SDavid du Colombier unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */
90*593dc095SDavid du Colombier } my_marker_writer;
91*593dc095SDavid du Colombier
92*593dc095SDavid du Colombier typedef my_marker_writer * my_marker_ptr;
93*593dc095SDavid du Colombier
94*593dc095SDavid du Colombier
957dd7cddfSDavid du Colombier /*
967dd7cddfSDavid du Colombier * Basic output routines.
977dd7cddfSDavid du Colombier *
987dd7cddfSDavid du Colombier * Note that we do not support suspension while writing a marker.
997dd7cddfSDavid du Colombier * Therefore, an application using suspension must ensure that there is
1007dd7cddfSDavid du Colombier * enough buffer space for the initial markers (typ. 600-700 bytes) before
1017dd7cddfSDavid du Colombier * calling jpeg_start_compress, and enough space to write the trailing EOI
1027dd7cddfSDavid du Colombier * (a few bytes) before calling jpeg_finish_compress. Multipass compression
1037dd7cddfSDavid du Colombier * modes are not supported at all with suspension, so those two are the only
1047dd7cddfSDavid du Colombier * points where markers will be written.
1057dd7cddfSDavid du Colombier */
1067dd7cddfSDavid du Colombier
1077dd7cddfSDavid du Colombier LOCAL(void)
emit_byte(j_compress_ptr cinfo,int val)1087dd7cddfSDavid du Colombier emit_byte (j_compress_ptr cinfo, int val)
1097dd7cddfSDavid du Colombier /* Emit a byte */
1107dd7cddfSDavid du Colombier {
1117dd7cddfSDavid du Colombier struct jpeg_destination_mgr * dest = cinfo->dest;
1127dd7cddfSDavid du Colombier
1137dd7cddfSDavid du Colombier *(dest->next_output_byte)++ = (JOCTET) val;
1147dd7cddfSDavid du Colombier if (--dest->free_in_buffer == 0) {
1157dd7cddfSDavid du Colombier if (! (*dest->empty_output_buffer) (cinfo))
1167dd7cddfSDavid du Colombier ERREXIT(cinfo, JERR_CANT_SUSPEND);
1177dd7cddfSDavid du Colombier }
1187dd7cddfSDavid du Colombier }
1197dd7cddfSDavid du Colombier
1207dd7cddfSDavid du Colombier
1217dd7cddfSDavid du Colombier LOCAL(void)
emit_marker(j_compress_ptr cinfo,JPEG_MARKER mark)1227dd7cddfSDavid du Colombier emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark)
1237dd7cddfSDavid du Colombier /* Emit a marker code */
1247dd7cddfSDavid du Colombier {
1257dd7cddfSDavid du Colombier emit_byte(cinfo, 0xFF);
1267dd7cddfSDavid du Colombier emit_byte(cinfo, (int) mark);
1277dd7cddfSDavid du Colombier }
1287dd7cddfSDavid du Colombier
1297dd7cddfSDavid du Colombier
1307dd7cddfSDavid du Colombier LOCAL(void)
emit_2bytes(j_compress_ptr cinfo,int value)1317dd7cddfSDavid du Colombier emit_2bytes (j_compress_ptr cinfo, int value)
1327dd7cddfSDavid du Colombier /* Emit a 2-byte integer; these are always MSB first in JPEG files */
1337dd7cddfSDavid du Colombier {
1347dd7cddfSDavid du Colombier emit_byte(cinfo, (value >> 8) & 0xFF);
1357dd7cddfSDavid du Colombier emit_byte(cinfo, value & 0xFF);
1367dd7cddfSDavid du Colombier }
1377dd7cddfSDavid du Colombier
1387dd7cddfSDavid du Colombier
1397dd7cddfSDavid du Colombier /*
1407dd7cddfSDavid du Colombier * Routines to write specific marker types.
1417dd7cddfSDavid du Colombier */
1427dd7cddfSDavid du Colombier
1437dd7cddfSDavid du Colombier LOCAL(int)
emit_dqt(j_compress_ptr cinfo,int index)1447dd7cddfSDavid du Colombier emit_dqt (j_compress_ptr cinfo, int index)
1457dd7cddfSDavid du Colombier /* Emit a DQT marker */
1467dd7cddfSDavid du Colombier /* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
1477dd7cddfSDavid du Colombier {
1487dd7cddfSDavid du Colombier JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index];
1497dd7cddfSDavid du Colombier int prec;
1507dd7cddfSDavid du Colombier int i;
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier if (qtbl == NULL)
1537dd7cddfSDavid du Colombier ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index);
1547dd7cddfSDavid du Colombier
1557dd7cddfSDavid du Colombier prec = 0;
1567dd7cddfSDavid du Colombier for (i = 0; i < DCTSIZE2; i++) {
1577dd7cddfSDavid du Colombier if (qtbl->quantval[i] > 255)
1587dd7cddfSDavid du Colombier prec = 1;
1597dd7cddfSDavid du Colombier }
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier if (! qtbl->sent_table) {
1627dd7cddfSDavid du Colombier emit_marker(cinfo, M_DQT);
1637dd7cddfSDavid du Colombier
1647dd7cddfSDavid du Colombier emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2);
1657dd7cddfSDavid du Colombier
1667dd7cddfSDavid du Colombier emit_byte(cinfo, index + (prec<<4));
1677dd7cddfSDavid du Colombier
1687dd7cddfSDavid du Colombier for (i = 0; i < DCTSIZE2; i++) {
1697dd7cddfSDavid du Colombier /* The table entries must be emitted in zigzag order. */
1707dd7cddfSDavid du Colombier unsigned int qval = qtbl->quantval[jpeg_natural_order[i]];
1717dd7cddfSDavid du Colombier if (prec)
172*593dc095SDavid du Colombier emit_byte(cinfo, (int) (qval >> 8));
173*593dc095SDavid du Colombier emit_byte(cinfo, (int) (qval & 0xFF));
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier
1767dd7cddfSDavid du Colombier qtbl->sent_table = TRUE;
1777dd7cddfSDavid du Colombier }
1787dd7cddfSDavid du Colombier
1797dd7cddfSDavid du Colombier return prec;
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier LOCAL(void)
emit_dht(j_compress_ptr cinfo,int index,boolean is_ac)1847dd7cddfSDavid du Colombier emit_dht (j_compress_ptr cinfo, int index, boolean is_ac)
1857dd7cddfSDavid du Colombier /* Emit a DHT marker */
1867dd7cddfSDavid du Colombier {
1877dd7cddfSDavid du Colombier JHUFF_TBL * htbl;
1887dd7cddfSDavid du Colombier int length, i;
1897dd7cddfSDavid du Colombier
1907dd7cddfSDavid du Colombier if (is_ac) {
1917dd7cddfSDavid du Colombier htbl = cinfo->ac_huff_tbl_ptrs[index];
1927dd7cddfSDavid du Colombier index += 0x10; /* output index has AC bit set */
1937dd7cddfSDavid du Colombier } else {
1947dd7cddfSDavid du Colombier htbl = cinfo->dc_huff_tbl_ptrs[index];
1957dd7cddfSDavid du Colombier }
1967dd7cddfSDavid du Colombier
1977dd7cddfSDavid du Colombier if (htbl == NULL)
1987dd7cddfSDavid du Colombier ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index);
1997dd7cddfSDavid du Colombier
2007dd7cddfSDavid du Colombier if (! htbl->sent_table) {
2017dd7cddfSDavid du Colombier emit_marker(cinfo, M_DHT);
2027dd7cddfSDavid du Colombier
2037dd7cddfSDavid du Colombier length = 0;
2047dd7cddfSDavid du Colombier for (i = 1; i <= 16; i++)
2057dd7cddfSDavid du Colombier length += htbl->bits[i];
2067dd7cddfSDavid du Colombier
2077dd7cddfSDavid du Colombier emit_2bytes(cinfo, length + 2 + 1 + 16);
2087dd7cddfSDavid du Colombier emit_byte(cinfo, index);
2097dd7cddfSDavid du Colombier
2107dd7cddfSDavid du Colombier for (i = 1; i <= 16; i++)
2117dd7cddfSDavid du Colombier emit_byte(cinfo, htbl->bits[i]);
2127dd7cddfSDavid du Colombier
2137dd7cddfSDavid du Colombier for (i = 0; i < length; i++)
2147dd7cddfSDavid du Colombier emit_byte(cinfo, htbl->huffval[i]);
2157dd7cddfSDavid du Colombier
2167dd7cddfSDavid du Colombier htbl->sent_table = TRUE;
2177dd7cddfSDavid du Colombier }
2187dd7cddfSDavid du Colombier }
2197dd7cddfSDavid du Colombier
2207dd7cddfSDavid du Colombier
2217dd7cddfSDavid du Colombier LOCAL(void)
emit_dac(j_compress_ptr cinfo)2227dd7cddfSDavid du Colombier emit_dac (j_compress_ptr cinfo)
2237dd7cddfSDavid du Colombier /* Emit a DAC marker */
2247dd7cddfSDavid du Colombier /* Since the useful info is so small, we want to emit all the tables in */
2257dd7cddfSDavid du Colombier /* one DAC marker. Therefore this routine does its own scan of the table. */
2267dd7cddfSDavid du Colombier {
2277dd7cddfSDavid du Colombier #ifdef C_ARITH_CODING_SUPPORTED
2287dd7cddfSDavid du Colombier char dc_in_use[NUM_ARITH_TBLS];
2297dd7cddfSDavid du Colombier char ac_in_use[NUM_ARITH_TBLS];
2307dd7cddfSDavid du Colombier int length, i;
2317dd7cddfSDavid du Colombier jpeg_component_info *compptr;
2327dd7cddfSDavid du Colombier
2337dd7cddfSDavid du Colombier for (i = 0; i < NUM_ARITH_TBLS; i++)
2347dd7cddfSDavid du Colombier dc_in_use[i] = ac_in_use[i] = 0;
2357dd7cddfSDavid du Colombier
2367dd7cddfSDavid du Colombier for (i = 0; i < cinfo->comps_in_scan; i++) {
2377dd7cddfSDavid du Colombier compptr = cinfo->cur_comp_info[i];
2387dd7cddfSDavid du Colombier dc_in_use[compptr->dc_tbl_no] = 1;
2397dd7cddfSDavid du Colombier ac_in_use[compptr->ac_tbl_no] = 1;
2407dd7cddfSDavid du Colombier }
2417dd7cddfSDavid du Colombier
2427dd7cddfSDavid du Colombier length = 0;
2437dd7cddfSDavid du Colombier for (i = 0; i < NUM_ARITH_TBLS; i++)
2447dd7cddfSDavid du Colombier length += dc_in_use[i] + ac_in_use[i];
2457dd7cddfSDavid du Colombier
2467dd7cddfSDavid du Colombier emit_marker(cinfo, M_DAC);
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier emit_2bytes(cinfo, length*2 + 2);
2497dd7cddfSDavid du Colombier
2507dd7cddfSDavid du Colombier for (i = 0; i < NUM_ARITH_TBLS; i++) {
2517dd7cddfSDavid du Colombier if (dc_in_use[i]) {
2527dd7cddfSDavid du Colombier emit_byte(cinfo, i);
2537dd7cddfSDavid du Colombier emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier if (ac_in_use[i]) {
2567dd7cddfSDavid du Colombier emit_byte(cinfo, i + 0x10);
2577dd7cddfSDavid du Colombier emit_byte(cinfo, cinfo->arith_ac_K[i]);
2587dd7cddfSDavid du Colombier }
2597dd7cddfSDavid du Colombier }
2607dd7cddfSDavid du Colombier #endif /* C_ARITH_CODING_SUPPORTED */
2617dd7cddfSDavid du Colombier }
2627dd7cddfSDavid du Colombier
2637dd7cddfSDavid du Colombier
2647dd7cddfSDavid du Colombier LOCAL(void)
emit_dri(j_compress_ptr cinfo)2657dd7cddfSDavid du Colombier emit_dri (j_compress_ptr cinfo)
2667dd7cddfSDavid du Colombier /* Emit a DRI marker */
2677dd7cddfSDavid du Colombier {
2687dd7cddfSDavid du Colombier emit_marker(cinfo, M_DRI);
2697dd7cddfSDavid du Colombier
2707dd7cddfSDavid du Colombier emit_2bytes(cinfo, 4); /* fixed length */
2717dd7cddfSDavid du Colombier
2727dd7cddfSDavid du Colombier emit_2bytes(cinfo, (int) cinfo->restart_interval);
2737dd7cddfSDavid du Colombier }
2747dd7cddfSDavid du Colombier
2757dd7cddfSDavid du Colombier
2767dd7cddfSDavid du Colombier LOCAL(void)
emit_sof(j_compress_ptr cinfo,JPEG_MARKER code)2777dd7cddfSDavid du Colombier emit_sof (j_compress_ptr cinfo, JPEG_MARKER code)
2787dd7cddfSDavid du Colombier /* Emit a SOF marker */
2797dd7cddfSDavid du Colombier {
2807dd7cddfSDavid du Colombier int ci;
2817dd7cddfSDavid du Colombier jpeg_component_info *compptr;
2827dd7cddfSDavid du Colombier
2837dd7cddfSDavid du Colombier emit_marker(cinfo, code);
2847dd7cddfSDavid du Colombier
2857dd7cddfSDavid du Colombier emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */
2867dd7cddfSDavid du Colombier
2877dd7cddfSDavid du Colombier /* Make sure image isn't bigger than SOF field can handle */
2887dd7cddfSDavid du Colombier if ((long) cinfo->image_height > 65535L ||
2897dd7cddfSDavid du Colombier (long) cinfo->image_width > 65535L)
2907dd7cddfSDavid du Colombier ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);
2917dd7cddfSDavid du Colombier
2927dd7cddfSDavid du Colombier emit_byte(cinfo, cinfo->data_precision);
2937dd7cddfSDavid du Colombier emit_2bytes(cinfo, (int) cinfo->image_height);
2947dd7cddfSDavid du Colombier emit_2bytes(cinfo, (int) cinfo->image_width);
2957dd7cddfSDavid du Colombier
2967dd7cddfSDavid du Colombier emit_byte(cinfo, cinfo->num_components);
2977dd7cddfSDavid du Colombier
2987dd7cddfSDavid du Colombier for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
2997dd7cddfSDavid du Colombier ci++, compptr++) {
3007dd7cddfSDavid du Colombier emit_byte(cinfo, compptr->component_id);
3017dd7cddfSDavid du Colombier emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor);
3027dd7cddfSDavid du Colombier emit_byte(cinfo, compptr->quant_tbl_no);
3037dd7cddfSDavid du Colombier }
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier
3067dd7cddfSDavid du Colombier
3077dd7cddfSDavid du Colombier LOCAL(void)
emit_sos(j_compress_ptr cinfo)3087dd7cddfSDavid du Colombier emit_sos (j_compress_ptr cinfo)
3097dd7cddfSDavid du Colombier /* Emit a SOS marker */
3107dd7cddfSDavid du Colombier {
3117dd7cddfSDavid du Colombier int i, td, ta;
3127dd7cddfSDavid du Colombier jpeg_component_info *compptr;
3137dd7cddfSDavid du Colombier
3147dd7cddfSDavid du Colombier emit_marker(cinfo, M_SOS);
3157dd7cddfSDavid du Colombier
3167dd7cddfSDavid du Colombier emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */
3177dd7cddfSDavid du Colombier
3187dd7cddfSDavid du Colombier emit_byte(cinfo, cinfo->comps_in_scan);
3197dd7cddfSDavid du Colombier
3207dd7cddfSDavid du Colombier for (i = 0; i < cinfo->comps_in_scan; i++) {
3217dd7cddfSDavid du Colombier compptr = cinfo->cur_comp_info[i];
3227dd7cddfSDavid du Colombier emit_byte(cinfo, compptr->component_id);
3237dd7cddfSDavid du Colombier td = compptr->dc_tbl_no;
3247dd7cddfSDavid du Colombier ta = compptr->ac_tbl_no;
3257dd7cddfSDavid du Colombier if (cinfo->progressive_mode) {
3267dd7cddfSDavid du Colombier /* Progressive mode: only DC or only AC tables are used in one scan;
3277dd7cddfSDavid du Colombier * furthermore, Huffman coding of DC refinement uses no table at all.
3287dd7cddfSDavid du Colombier * We emit 0 for unused field(s); this is recommended by the P&M text
3297dd7cddfSDavid du Colombier * but does not seem to be specified in the standard.
3307dd7cddfSDavid du Colombier */
3317dd7cddfSDavid du Colombier if (cinfo->Ss == 0) {
3327dd7cddfSDavid du Colombier ta = 0; /* DC scan */
3337dd7cddfSDavid du Colombier if (cinfo->Ah != 0 && !cinfo->arith_code)
3347dd7cddfSDavid du Colombier td = 0; /* no DC table either */
3357dd7cddfSDavid du Colombier } else {
3367dd7cddfSDavid du Colombier td = 0; /* AC scan */
3377dd7cddfSDavid du Colombier }
3387dd7cddfSDavid du Colombier }
3397dd7cddfSDavid du Colombier emit_byte(cinfo, (td << 4) + ta);
3407dd7cddfSDavid du Colombier }
3417dd7cddfSDavid du Colombier
3427dd7cddfSDavid du Colombier emit_byte(cinfo, cinfo->Ss);
3437dd7cddfSDavid du Colombier emit_byte(cinfo, cinfo->Se);
3447dd7cddfSDavid du Colombier emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al);
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier
3487dd7cddfSDavid du Colombier LOCAL(void)
emit_jfif_app0(j_compress_ptr cinfo)3497dd7cddfSDavid du Colombier emit_jfif_app0 (j_compress_ptr cinfo)
3507dd7cddfSDavid du Colombier /* Emit a JFIF-compliant APP0 marker */
3517dd7cddfSDavid du Colombier {
3527dd7cddfSDavid du Colombier /*
3537dd7cddfSDavid du Colombier * Length of APP0 block (2 bytes)
3547dd7cddfSDavid du Colombier * Block ID (4 bytes - ASCII "JFIF")
3557dd7cddfSDavid du Colombier * Zero byte (1 byte to terminate the ID string)
356*593dc095SDavid du Colombier * Version Major, Minor (2 bytes - major first)
3577dd7cddfSDavid du Colombier * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)
3587dd7cddfSDavid du Colombier * Xdpu (2 bytes - dots per unit horizontal)
3597dd7cddfSDavid du Colombier * Ydpu (2 bytes - dots per unit vertical)
3607dd7cddfSDavid du Colombier * Thumbnail X size (1 byte)
3617dd7cddfSDavid du Colombier * Thumbnail Y size (1 byte)
3627dd7cddfSDavid du Colombier */
3637dd7cddfSDavid du Colombier
3647dd7cddfSDavid du Colombier emit_marker(cinfo, M_APP0);
3657dd7cddfSDavid du Colombier
3667dd7cddfSDavid du Colombier emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */
3677dd7cddfSDavid du Colombier
3687dd7cddfSDavid du Colombier emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */
3697dd7cddfSDavid du Colombier emit_byte(cinfo, 0x46);
3707dd7cddfSDavid du Colombier emit_byte(cinfo, 0x49);
3717dd7cddfSDavid du Colombier emit_byte(cinfo, 0x46);
3727dd7cddfSDavid du Colombier emit_byte(cinfo, 0);
373*593dc095SDavid du Colombier emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */
374*593dc095SDavid du Colombier emit_byte(cinfo, cinfo->JFIF_minor_version);
3757dd7cddfSDavid du Colombier emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */
3767dd7cddfSDavid du Colombier emit_2bytes(cinfo, (int) cinfo->X_density);
3777dd7cddfSDavid du Colombier emit_2bytes(cinfo, (int) cinfo->Y_density);
3787dd7cddfSDavid du Colombier emit_byte(cinfo, 0); /* No thumbnail image */
3797dd7cddfSDavid du Colombier emit_byte(cinfo, 0);
3807dd7cddfSDavid du Colombier }
3817dd7cddfSDavid du Colombier
3827dd7cddfSDavid du Colombier
3837dd7cddfSDavid du Colombier LOCAL(void)
emit_adobe_app14(j_compress_ptr cinfo)3847dd7cddfSDavid du Colombier emit_adobe_app14 (j_compress_ptr cinfo)
3857dd7cddfSDavid du Colombier /* Emit an Adobe APP14 marker */
3867dd7cddfSDavid du Colombier {
3877dd7cddfSDavid du Colombier /*
3887dd7cddfSDavid du Colombier * Length of APP14 block (2 bytes)
3897dd7cddfSDavid du Colombier * Block ID (5 bytes - ASCII "Adobe")
3907dd7cddfSDavid du Colombier * Version Number (2 bytes - currently 100)
3917dd7cddfSDavid du Colombier * Flags0 (2 bytes - currently 0)
3927dd7cddfSDavid du Colombier * Flags1 (2 bytes - currently 0)
3937dd7cddfSDavid du Colombier * Color transform (1 byte)
3947dd7cddfSDavid du Colombier *
3957dd7cddfSDavid du Colombier * Although Adobe TN 5116 mentions Version = 101, all the Adobe files
3967dd7cddfSDavid du Colombier * now in circulation seem to use Version = 100, so that's what we write.
3977dd7cddfSDavid du Colombier *
3987dd7cddfSDavid du Colombier * We write the color transform byte as 1 if the JPEG color space is
3997dd7cddfSDavid du Colombier * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with
4007dd7cddfSDavid du Colombier * whether the encoder performed a transformation, which is pretty useless.
4017dd7cddfSDavid du Colombier */
4027dd7cddfSDavid du Colombier
4037dd7cddfSDavid du Colombier emit_marker(cinfo, M_APP14);
4047dd7cddfSDavid du Colombier
4057dd7cddfSDavid du Colombier emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */
4067dd7cddfSDavid du Colombier
4077dd7cddfSDavid du Colombier emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */
4087dd7cddfSDavid du Colombier emit_byte(cinfo, 0x64);
4097dd7cddfSDavid du Colombier emit_byte(cinfo, 0x6F);
4107dd7cddfSDavid du Colombier emit_byte(cinfo, 0x62);
4117dd7cddfSDavid du Colombier emit_byte(cinfo, 0x65);
4127dd7cddfSDavid du Colombier emit_2bytes(cinfo, 100); /* Version */
4137dd7cddfSDavid du Colombier emit_2bytes(cinfo, 0); /* Flags0 */
4147dd7cddfSDavid du Colombier emit_2bytes(cinfo, 0); /* Flags1 */
4157dd7cddfSDavid du Colombier switch (cinfo->jpeg_color_space) {
4167dd7cddfSDavid du Colombier case JCS_YCbCr:
4177dd7cddfSDavid du Colombier emit_byte(cinfo, 1); /* Color transform = 1 */
4187dd7cddfSDavid du Colombier break;
4197dd7cddfSDavid du Colombier case JCS_YCCK:
4207dd7cddfSDavid du Colombier emit_byte(cinfo, 2); /* Color transform = 2 */
4217dd7cddfSDavid du Colombier break;
4227dd7cddfSDavid du Colombier default:
4237dd7cddfSDavid du Colombier emit_byte(cinfo, 0); /* Color transform = 0 */
4247dd7cddfSDavid du Colombier break;
4257dd7cddfSDavid du Colombier }
4267dd7cddfSDavid du Colombier }
4277dd7cddfSDavid du Colombier
4287dd7cddfSDavid du Colombier
4297dd7cddfSDavid du Colombier /*
430*593dc095SDavid du Colombier * These routines allow writing an arbitrary marker with parameters.
431*593dc095SDavid du Colombier * The only intended use is to emit COM or APPn markers after calling
432*593dc095SDavid du Colombier * write_file_header and before calling write_frame_header.
4337dd7cddfSDavid du Colombier * Other uses are not guaranteed to produce desirable results.
434*593dc095SDavid du Colombier * Counting the parameter bytes properly is the caller's responsibility.
4357dd7cddfSDavid du Colombier */
4367dd7cddfSDavid du Colombier
4377dd7cddfSDavid du Colombier METHODDEF(void)
write_marker_header(j_compress_ptr cinfo,int marker,unsigned int datalen)438*593dc095SDavid du Colombier write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen)
439*593dc095SDavid du Colombier /* Emit an arbitrary marker header */
4407dd7cddfSDavid du Colombier {
441*593dc095SDavid du Colombier if (datalen > (unsigned int) 65533) /* safety check */
442*593dc095SDavid du Colombier ERREXIT(cinfo, JERR_BAD_LENGTH);
443*593dc095SDavid du Colombier
4447dd7cddfSDavid du Colombier emit_marker(cinfo, (JPEG_MARKER) marker);
4457dd7cddfSDavid du Colombier
4467dd7cddfSDavid du Colombier emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */
447*593dc095SDavid du Colombier }
4487dd7cddfSDavid du Colombier
449*593dc095SDavid du Colombier METHODDEF(void)
write_marker_byte(j_compress_ptr cinfo,int val)450*593dc095SDavid du Colombier write_marker_byte (j_compress_ptr cinfo, int val)
451*593dc095SDavid du Colombier /* Emit one byte of marker parameters following write_marker_header */
452*593dc095SDavid du Colombier {
453*593dc095SDavid du Colombier emit_byte(cinfo, val);
4547dd7cddfSDavid du Colombier }
4557dd7cddfSDavid du Colombier
4567dd7cddfSDavid du Colombier
4577dd7cddfSDavid du Colombier /*
4587dd7cddfSDavid du Colombier * Write datastream header.
4597dd7cddfSDavid du Colombier * This consists of an SOI and optional APPn markers.
4607dd7cddfSDavid du Colombier * We recommend use of the JFIF marker, but not the Adobe marker,
4617dd7cddfSDavid du Colombier * when using YCbCr or grayscale data. The JFIF marker should NOT
4627dd7cddfSDavid du Colombier * be used for any other JPEG colorspace. The Adobe marker is helpful
4637dd7cddfSDavid du Colombier * to distinguish RGB, CMYK, and YCCK colorspaces.
4647dd7cddfSDavid du Colombier * Note that an application can write additional header markers after
4657dd7cddfSDavid du Colombier * jpeg_start_compress returns.
4667dd7cddfSDavid du Colombier */
4677dd7cddfSDavid du Colombier
4687dd7cddfSDavid du Colombier METHODDEF(void)
write_file_header(j_compress_ptr cinfo)4697dd7cddfSDavid du Colombier write_file_header (j_compress_ptr cinfo)
4707dd7cddfSDavid du Colombier {
471*593dc095SDavid du Colombier my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
472*593dc095SDavid du Colombier
4737dd7cddfSDavid du Colombier emit_marker(cinfo, M_SOI); /* first the SOI */
4747dd7cddfSDavid du Colombier
475*593dc095SDavid du Colombier /* SOI is defined to reset restart interval to 0 */
476*593dc095SDavid du Colombier marker->last_restart_interval = 0;
477*593dc095SDavid du Colombier
4787dd7cddfSDavid du Colombier if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */
4797dd7cddfSDavid du Colombier emit_jfif_app0(cinfo);
4807dd7cddfSDavid du Colombier if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */
4817dd7cddfSDavid du Colombier emit_adobe_app14(cinfo);
4827dd7cddfSDavid du Colombier }
4837dd7cddfSDavid du Colombier
4847dd7cddfSDavid du Colombier
4857dd7cddfSDavid du Colombier /*
4867dd7cddfSDavid du Colombier * Write frame header.
4877dd7cddfSDavid du Colombier * This consists of DQT and SOFn markers.
4887dd7cddfSDavid du Colombier * Note that we do not emit the SOF until we have emitted the DQT(s).
4897dd7cddfSDavid du Colombier * This avoids compatibility problems with incorrect implementations that
4907dd7cddfSDavid du Colombier * try to error-check the quant table numbers as soon as they see the SOF.
4917dd7cddfSDavid du Colombier */
4927dd7cddfSDavid du Colombier
4937dd7cddfSDavid du Colombier METHODDEF(void)
write_frame_header(j_compress_ptr cinfo)4947dd7cddfSDavid du Colombier write_frame_header (j_compress_ptr cinfo)
4957dd7cddfSDavid du Colombier {
4967dd7cddfSDavid du Colombier int ci, prec;
4977dd7cddfSDavid du Colombier boolean is_baseline;
4987dd7cddfSDavid du Colombier jpeg_component_info *compptr;
4997dd7cddfSDavid du Colombier
5007dd7cddfSDavid du Colombier /* Emit DQT for each quantization table.
5017dd7cddfSDavid du Colombier * Note that emit_dqt() suppresses any duplicate tables.
5027dd7cddfSDavid du Colombier */
5037dd7cddfSDavid du Colombier prec = 0;
5047dd7cddfSDavid du Colombier for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
5057dd7cddfSDavid du Colombier ci++, compptr++) {
5067dd7cddfSDavid du Colombier prec += emit_dqt(cinfo, compptr->quant_tbl_no);
5077dd7cddfSDavid du Colombier }
5087dd7cddfSDavid du Colombier /* now prec is nonzero iff there are any 16-bit quant tables. */
5097dd7cddfSDavid du Colombier
5107dd7cddfSDavid du Colombier /* Check for a non-baseline specification.
5117dd7cddfSDavid du Colombier * Note we assume that Huffman table numbers won't be changed later.
5127dd7cddfSDavid du Colombier */
5137dd7cddfSDavid du Colombier if (cinfo->arith_code || cinfo->progressive_mode ||
5147dd7cddfSDavid du Colombier cinfo->data_precision != 8) {
5157dd7cddfSDavid du Colombier is_baseline = FALSE;
5167dd7cddfSDavid du Colombier } else {
5177dd7cddfSDavid du Colombier is_baseline = TRUE;
5187dd7cddfSDavid du Colombier for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
5197dd7cddfSDavid du Colombier ci++, compptr++) {
5207dd7cddfSDavid du Colombier if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1)
5217dd7cddfSDavid du Colombier is_baseline = FALSE;
5227dd7cddfSDavid du Colombier }
5237dd7cddfSDavid du Colombier if (prec && is_baseline) {
5247dd7cddfSDavid du Colombier is_baseline = FALSE;
5257dd7cddfSDavid du Colombier /* If it's baseline except for quantizer size, warn the user */
5267dd7cddfSDavid du Colombier TRACEMS(cinfo, 0, JTRC_16BIT_TABLES);
5277dd7cddfSDavid du Colombier }
5287dd7cddfSDavid du Colombier }
5297dd7cddfSDavid du Colombier
5307dd7cddfSDavid du Colombier /* Emit the proper SOF marker */
5317dd7cddfSDavid du Colombier if (cinfo->arith_code) {
5327dd7cddfSDavid du Colombier emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */
5337dd7cddfSDavid du Colombier } else {
5347dd7cddfSDavid du Colombier if (cinfo->progressive_mode)
5357dd7cddfSDavid du Colombier emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */
5367dd7cddfSDavid du Colombier else if (is_baseline)
5377dd7cddfSDavid du Colombier emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */
5387dd7cddfSDavid du Colombier else
5397dd7cddfSDavid du Colombier emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */
5407dd7cddfSDavid du Colombier }
5417dd7cddfSDavid du Colombier }
5427dd7cddfSDavid du Colombier
5437dd7cddfSDavid du Colombier
5447dd7cddfSDavid du Colombier /*
5457dd7cddfSDavid du Colombier * Write scan header.
5467dd7cddfSDavid du Colombier * This consists of DHT or DAC markers, optional DRI, and SOS.
5477dd7cddfSDavid du Colombier * Compressed data will be written following the SOS.
5487dd7cddfSDavid du Colombier */
5497dd7cddfSDavid du Colombier
5507dd7cddfSDavid du Colombier METHODDEF(void)
write_scan_header(j_compress_ptr cinfo)5517dd7cddfSDavid du Colombier write_scan_header (j_compress_ptr cinfo)
5527dd7cddfSDavid du Colombier {
553*593dc095SDavid du Colombier my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
5547dd7cddfSDavid du Colombier int i;
5557dd7cddfSDavid du Colombier jpeg_component_info *compptr;
5567dd7cddfSDavid du Colombier
5577dd7cddfSDavid du Colombier if (cinfo->arith_code) {
5587dd7cddfSDavid du Colombier /* Emit arith conditioning info. We may have some duplication
5597dd7cddfSDavid du Colombier * if the file has multiple scans, but it's so small it's hardly
5607dd7cddfSDavid du Colombier * worth worrying about.
5617dd7cddfSDavid du Colombier */
5627dd7cddfSDavid du Colombier emit_dac(cinfo);
5637dd7cddfSDavid du Colombier } else {
5647dd7cddfSDavid du Colombier /* Emit Huffman tables.
5657dd7cddfSDavid du Colombier * Note that emit_dht() suppresses any duplicate tables.
5667dd7cddfSDavid du Colombier */
5677dd7cddfSDavid du Colombier for (i = 0; i < cinfo->comps_in_scan; i++) {
5687dd7cddfSDavid du Colombier compptr = cinfo->cur_comp_info[i];
5697dd7cddfSDavid du Colombier if (cinfo->progressive_mode) {
5707dd7cddfSDavid du Colombier /* Progressive mode: only DC or only AC tables are used in one scan */
5717dd7cddfSDavid du Colombier if (cinfo->Ss == 0) {
5727dd7cddfSDavid du Colombier if (cinfo->Ah == 0) /* DC needs no table for refinement scan */
5737dd7cddfSDavid du Colombier emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
5747dd7cddfSDavid du Colombier } else {
5757dd7cddfSDavid du Colombier emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
5767dd7cddfSDavid du Colombier }
5777dd7cddfSDavid du Colombier } else {
5787dd7cddfSDavid du Colombier /* Sequential mode: need both DC and AC tables */
5797dd7cddfSDavid du Colombier emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
5807dd7cddfSDavid du Colombier emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
5817dd7cddfSDavid du Colombier }
5827dd7cddfSDavid du Colombier }
5837dd7cddfSDavid du Colombier }
5847dd7cddfSDavid du Colombier
5857dd7cddfSDavid du Colombier /* Emit DRI if required --- note that DRI value could change for each scan.
586*593dc095SDavid du Colombier * We avoid wasting space with unnecessary DRIs, however.
5877dd7cddfSDavid du Colombier */
588*593dc095SDavid du Colombier if (cinfo->restart_interval != marker->last_restart_interval) {
5897dd7cddfSDavid du Colombier emit_dri(cinfo);
590*593dc095SDavid du Colombier marker->last_restart_interval = cinfo->restart_interval;
591*593dc095SDavid du Colombier }
5927dd7cddfSDavid du Colombier
5937dd7cddfSDavid du Colombier emit_sos(cinfo);
5947dd7cddfSDavid du Colombier }
5957dd7cddfSDavid du Colombier
5967dd7cddfSDavid du Colombier
5977dd7cddfSDavid du Colombier /*
5987dd7cddfSDavid du Colombier * Write datastream trailer.
5997dd7cddfSDavid du Colombier */
6007dd7cddfSDavid du Colombier
6017dd7cddfSDavid du Colombier METHODDEF(void)
write_file_trailer(j_compress_ptr cinfo)6027dd7cddfSDavid du Colombier write_file_trailer (j_compress_ptr cinfo)
6037dd7cddfSDavid du Colombier {
6047dd7cddfSDavid du Colombier emit_marker(cinfo, M_EOI);
6057dd7cddfSDavid du Colombier }
6067dd7cddfSDavid du Colombier
6077dd7cddfSDavid du Colombier
6087dd7cddfSDavid du Colombier /*
6097dd7cddfSDavid du Colombier * Write an abbreviated table-specification datastream.
6107dd7cddfSDavid du Colombier * This consists of SOI, DQT and DHT tables, and EOI.
6117dd7cddfSDavid du Colombier * Any table that is defined and not marked sent_table = TRUE will be
6127dd7cddfSDavid du Colombier * emitted. Note that all tables will be marked sent_table = TRUE at exit.
6137dd7cddfSDavid du Colombier */
6147dd7cddfSDavid du Colombier
6157dd7cddfSDavid du Colombier METHODDEF(void)
write_tables_only(j_compress_ptr cinfo)6167dd7cddfSDavid du Colombier write_tables_only (j_compress_ptr cinfo)
6177dd7cddfSDavid du Colombier {
6187dd7cddfSDavid du Colombier int i;
6197dd7cddfSDavid du Colombier
6207dd7cddfSDavid du Colombier emit_marker(cinfo, M_SOI);
6217dd7cddfSDavid du Colombier
6227dd7cddfSDavid du Colombier for (i = 0; i < NUM_QUANT_TBLS; i++) {
6237dd7cddfSDavid du Colombier if (cinfo->quant_tbl_ptrs[i] != NULL)
6247dd7cddfSDavid du Colombier (void) emit_dqt(cinfo, i);
6257dd7cddfSDavid du Colombier }
6267dd7cddfSDavid du Colombier
6277dd7cddfSDavid du Colombier if (! cinfo->arith_code) {
6287dd7cddfSDavid du Colombier for (i = 0; i < NUM_HUFF_TBLS; i++) {
6297dd7cddfSDavid du Colombier if (cinfo->dc_huff_tbl_ptrs[i] != NULL)
6307dd7cddfSDavid du Colombier emit_dht(cinfo, i, FALSE);
6317dd7cddfSDavid du Colombier if (cinfo->ac_huff_tbl_ptrs[i] != NULL)
6327dd7cddfSDavid du Colombier emit_dht(cinfo, i, TRUE);
6337dd7cddfSDavid du Colombier }
6347dd7cddfSDavid du Colombier }
6357dd7cddfSDavid du Colombier
6367dd7cddfSDavid du Colombier emit_marker(cinfo, M_EOI);
6377dd7cddfSDavid du Colombier }
6387dd7cddfSDavid du Colombier
6397dd7cddfSDavid du Colombier
6407dd7cddfSDavid du Colombier /*
6417dd7cddfSDavid du Colombier * Initialize the marker writer module.
6427dd7cddfSDavid du Colombier */
6437dd7cddfSDavid du Colombier
6447dd7cddfSDavid du Colombier GLOBAL(void)
jinit_marker_writer(j_compress_ptr cinfo)6457dd7cddfSDavid du Colombier jinit_marker_writer (j_compress_ptr cinfo)
6467dd7cddfSDavid du Colombier {
647*593dc095SDavid du Colombier my_marker_ptr marker;
648*593dc095SDavid du Colombier
6497dd7cddfSDavid du Colombier /* Create the subobject */
650*593dc095SDavid du Colombier marker = (my_marker_ptr)
6517dd7cddfSDavid du Colombier (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
652*593dc095SDavid du Colombier SIZEOF(my_marker_writer));
653*593dc095SDavid du Colombier cinfo->marker = (struct jpeg_marker_writer *) marker;
6547dd7cddfSDavid du Colombier /* Initialize method pointers */
655*593dc095SDavid du Colombier marker->pub.write_file_header = write_file_header;
656*593dc095SDavid du Colombier marker->pub.write_frame_header = write_frame_header;
657*593dc095SDavid du Colombier marker->pub.write_scan_header = write_scan_header;
658*593dc095SDavid du Colombier marker->pub.write_file_trailer = write_file_trailer;
659*593dc095SDavid du Colombier marker->pub.write_tables_only = write_tables_only;
660*593dc095SDavid du Colombier marker->pub.write_marker_header = write_marker_header;
661*593dc095SDavid du Colombier marker->pub.write_marker_byte = write_marker_byte;
662*593dc095SDavid du Colombier /* Initialize private state */
663*593dc095SDavid du Colombier marker->last_restart_interval = 0;
6647dd7cddfSDavid du Colombier }
665