summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorOliver Schinagl <oliver@schinagl.nl>2005-06-09 13:29:06 (GMT)
committerOliver Schinagl <oliver@schinagl.nl>2005-06-09 13:29:06 (GMT)
commit96fc83255a1e9985c5b7b28d4c2dc5e422771a57 (patch)
tree926b7c3b528bfbaf589236b3e444ca9f2f163a5a /src
parent2510951cf838f826892a767ebb1f639dcc192cc9 (diff)
download5kk53-96fc83255a1e9985c5b7b28d4c2dc5e422771a57.zip
5kk53-96fc83255a1e9985c5b7b28d4c2dc5e422771a57.tar.gz
5kk53-96fc83255a1e9985c5b7b28d4c2dc5e422771a57.tar.bz2
Functions to write markers
Diffstat (limited to 'src')
-rw-r--r--src/c_marker.c724
1 files changed, 724 insertions, 0 deletions
diff --git a/src/c_marker.c b/src/c_marker.c
new file mode 100644
index 0000000..c6e1837
--- /dev/null
+++ b/src/c_marker.c
@@ -0,0 +1,724 @@
+/*
+ * jcmarker.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write JPEG datastream markers.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "morecfg.h"
+#include "jpeglib.h"
+
+/*
+ * jpeg_natural_order[i] is the natural-order position of the i'th element
+ * of zigzag order.
+ *
+ * When reading corrupted data, the Huffman decoders could attempt
+ * to reference an entry beyond the end of this array (if the decoded
+ * zero run length reaches past the end of the block). To prevent
+ * wild stores without adding an inner-loop test, we put some extra
+ * "63"s after the real entries. This will cause the extra coefficient
+ * to be stored in location 63 of the block, not somewhere random.
+ * The worst case would be a run-length of 15, which means we need 16
+ * fake entries.
+ */
+
+const int jpeg_natural_order[DCTSIZE2+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+
+typedef enum { /* JPEG marker codes */
+ M_SOF0 = 0xc0,
+ M_SOF1 = 0xc1,
+ M_SOF2 = 0xc2,
+ M_SOF3 = 0xc3,
+
+ M_SOF5 = 0xc5,
+ M_SOF6 = 0xc6,
+ M_SOF7 = 0xc7,
+
+ M_JPG = 0xc8,
+ M_SOF9 = 0xc9,
+ M_SOF10 = 0xca,
+ M_SOF11 = 0xcb,
+
+ M_SOF13 = 0xcd,
+ M_SOF14 = 0xce,
+ M_SOF15 = 0xcf,
+
+ M_DHT = 0xc4,
+
+ M_DAC = 0xcc,
+
+ M_RST0 = 0xd0,
+ M_RST1 = 0xd1,
+ M_RST2 = 0xd2,
+ M_RST3 = 0xd3,
+ M_RST4 = 0xd4,
+ M_RST5 = 0xd5,
+ M_RST6 = 0xd6,
+ M_RST7 = 0xd7,
+
+ M_SOI = 0xd8,
+ M_EOI = 0xd9,
+ M_SOS = 0xda,
+ M_DQT = 0xdb,
+ M_DNL = 0xdc,
+ M_DRI = 0xdd,
+ M_DHP = 0xde,
+ M_EXP = 0xdf,
+
+ M_APP0 = 0xe0,
+ M_APP1 = 0xe1,
+ M_APP2 = 0xe2,
+ M_APP3 = 0xe3,
+ M_APP4 = 0xe4,
+ M_APP5 = 0xe5,
+ M_APP6 = 0xe6,
+ M_APP7 = 0xe7,
+ M_APP8 = 0xe8,
+ M_APP9 = 0xe9,
+ M_APP10 = 0xea,
+ M_APP11 = 0xeb,
+ M_APP12 = 0xec,
+ M_APP13 = 0xed,
+ M_APP14 = 0xee,
+ M_APP15 = 0xef,
+
+ M_JPG0 = 0xf0,
+ M_JPG13 = 0xfd,
+ M_COM = 0xfe,
+
+ M_TEM = 0x01,
+
+ M_ERROR = 0x100
+} JPEG_MARKER;
+
+#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
+
+/* Expanded data destination object for stdio output */
+
+typedef struct {
+ struct jpeg_destination_mgr pub; /* public fields */
+
+ FILE *outfile; /* target stream */
+ JOCTET buffer[OUTPUT_BUF_SIZE]; /* start of buffer */
+} my_destination_mgr;
+
+
+/*
+ * Empty the output buffer --- called whenever buffer fills up.
+ *
+ * In typical applications, this should write the entire output buffer
+ * (ignoring the current state of next_output_byte & free_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been dumped.
+ *
+ * In applications that need to be able to suspend compression due to output
+ * overrun, a FALSE return indicates that the buffer cannot be emptied now.
+ * In this situation, the compressor will return to its caller (possibly with
+ * an indication that it has not accepted all the supplied scanlines). The
+ * application should resume compression after it has made more room in the
+ * output buffer. Note that there are substantial restrictions on the use of
+ * suspension --- see the documentation.
+ *
+ * When suspending, the compressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_output_byte & free_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point will be regenerated after resumption, so do not
+ * write it out when emptying the buffer externally.
+ */
+
+boolean empty_output_buffer (my_destination_mgr *destination) {
+ my_destination_mgr *dest = destination;
+
+ if (fwrite(dest->buffer, 1, OUTPUT_BUF_SIZE, dest->outfile) != OUTPUT_BUF_SIZE) {
+ perror("Output file write error --- out of disk space?");
+ exit(1);
+ /* ERREXIT(cinfo, JERR_FILE_WRITE);*/
+ }
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+
+ return TRUE;
+}
+
+
+/*
+ * Basic output routines.
+ *
+ * Note that we do not support suspension while writing a marker.
+ * Therefore, an application using suspension must ensure that there is
+ * enough buffer space for the initial markers (typ. 600-700 bytes) before
+ * calling jpeg_start_compress, and enough space to write the trailing EOI
+ * (a few bytes) before calling jpeg_finish_compress. Multipass compression
+ * modes are not supported at all with suspension, so those two are the only
+ * points where markers will be written.
+ */
+
+void emit_byte (my_destination_mgr *destination, int val) /* Emit a byte */ {
+ my_destination_mgr *dest = destination;
+
+ *(dest->pub.next_output_byte)++ = (JOCTET) val;
+ if ((--dest->pub.free_in_buffer) == 0) {
+ if (! empty_output_buffer(destination)) {
+ perror("Suspension not allowed here");
+ exit(1);
+ /*ERREXIT(cinfo, JERR_CANT_SUSPEND);*/
+ }
+ }
+}
+
+static void emit_marker (my_destination_mgr *destination, JPEG_MARKER mark) /* Emit a marker code */ {
+ emit_byte(destination, 0xFF);
+ emit_byte(destination, (int) mark);
+}
+
+
+static void emit_2bytes (my_destination_mgr *destination, int value) /* Emit a 2-byte integer; these are always MSB first in JPEG files */ {
+ emit_byte(destination, (value >> 8) & 0xFF);
+ emit_byte(destination, value & 0xFF);
+}
+
+
+/*
+ * Routines to write specific marker types.
+ */
+
+int emit_dqt (my_destination_mgr *destination, int index)
+/* Emit a DQT marker */
+/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
+{
+ /* Quantization table is externally globally defined */
+ extern JQUANT_TBL qtbl;
+ int prec;
+ int i;
+
+ if (qtbl.quantval == NULL) {
+ perror("Quantization table 0x%%02x was not defined");
+ exit(1);
+ /*ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index);*/
+ }
+ prec = 0;
+ for (i = 0; i < DCTSIZE2; i++) {
+ if (qtbl.quantval[i] > 255)
+ prec = 1;
+ }
+
+ if (! qtbl.sent_table) {
+ emit_marker(destination, M_DQT);
+
+ emit_2bytes(destination, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2);
+
+ emit_byte(destination, index + (prec<<4));
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ /* The table entries must be emitted in zigzag order. */
+ unsigned int qval = qtbl.quantval[i];
+
+ if (prec) {
+ emit_byte(destination, (int) (qval >> 8));
+ }
+ emit_byte(destination, (int) (qval & 0xFF));
+ }
+
+ qtbl.sent_table = TRUE;
+ }
+ return prec;
+}
+
+
+static void emit_dht (my_destination_mgr *destination, int index, boolean is_ac)
+/* Emit a DHT marker */
+{
+ extern JHUFF_TBL ac_Huffman_Table[];
+ extern JHUFF_TBL dc_Huffman_Table[];
+ JHUFF_TBL *htbl;
+ int length, i;
+
+ if (is_ac) {
+ htbl = ac_Huffman_Table;
+ index += 0x10; /* output index has AC bit set */
+ } else {
+ htbl = dc_Huffman_Table;
+ }
+
+ if (htbl == NULL){
+ perror("Huffman table 0x%%02x was not defined");
+ exit(1);
+ /*ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index);*/
+ }
+ if (! htbl->sent_table) {
+ emit_marker(destination, M_DHT);
+
+ length = 0;
+ for (i = 1; i <= 16; i++)
+ length += htbl->bits[i];
+
+ emit_2bytes(destination, length + 2 + 1 + 16);
+ emit_byte(destination, index);
+
+ for (i = 1; i <= 16; i++)
+ emit_byte(destination, htbl->bits[i]);
+
+ for (i = 0; i < length; i++)
+ emit_byte(destination, htbl->huffval[i]);
+
+ htbl->sent_table = TRUE;
+ }
+}
+
+
+#if 0
+static void emit_dac (j_compress_ptr cinfo)
+/* Emit a DAC marker */
+/* Since the useful info is so small, we want to emit all the tables in */
+/* one DAC marker. Therefore this routine does its own scan of the table. */
+{
+#ifdef C_ARITH_CODING_SUPPORTED
+ char dc_in_use[NUM_ARITH_TBLS];
+ char ac_in_use[NUM_ARITH_TBLS];
+ int length, i;
+ jpeg_component_info *compptr;
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++)
+ dc_in_use[i] = ac_in_use[i] = 0;
+
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ compptr = cinfo->cur_comp_info[i];
+ dc_in_use[compptr->dc_tbl_no] = 1;
+ ac_in_use[compptr->ac_tbl_no] = 1;
+ }
+
+ length = 0;
+ for (i = 0; i < NUM_ARITH_TBLS; i++)
+ length += dc_in_use[i] + ac_in_use[i];
+
+ emit_marker(cinfo, M_DAC);
+
+ emit_2bytes(cinfo, length*2 + 2);
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ if (dc_in_use[i]) {
+ emit_byte(cinfo, i);
+ emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));
+ }
+ if (ac_in_use[i]) {
+ emit_byte(cinfo, i + 0x10);
+ emit_byte(cinfo, cinfo->arith_ac_K[i]);
+ }
+ }
+#endif /* C_ARITH_CODING_SUPPORTED */
+}
+
+
+static void emit_dri (j_compress_ptr cinfo)
+/* Emit a DRI marker */
+{
+ emit_marker(cinfo, M_DRI);
+
+ emit_2bytes(cinfo, 4); /* fixed length */
+
+ emit_2bytes(cinfo, (int) cinfo->restart_interval);
+}
+#endif
+
+static void emit_sof(my_destination_mgr *destination, JPEG_MARKER code, int image_height, int image_width)
+/* Emit a SOF marker */
+{
+ int ci;
+ int num_components = 1;
+ jpeg_component_info *compptr;
+
+ emit_marker(destination, code);
+
+ emit_2bytes(destination, 3 * num_components + 2 + 5 + 1); /* length */
+
+ /* Make sure image isn't bigger than SOF field can handle */
+ if ((long) image_height > 65535L ||
+ (long) image_width > 65535L) {
+ perror("Maximum supported image dimension is %u pixels");
+ exit(1);
+ /*ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);*/
+ }
+ emit_byte(destination, 8);
+ emit_2bytes(destination, image_height);
+ emit_2bytes(destination, image_width);
+
+ emit_byte(destination, num_components);
+
+ emit_byte(destination, 1);
+ emit_byte(destination, 0x22);
+ emit_byte(destination, 0);
+/*
+ for (ci = 0, compptr = cinfo->comp_info; ci < num_components; ci++, compptr++) {
+ emit_byte(destination, compptr->component_id);
+ emit_byte(destination, (compptr->h_samp_factor << 4) + compptr->v_samp_factor);
+ emit_byte(destination, compptr->quant_tbl_no);
+ }
+ */
+}
+
+static void emit_sos (my_destination_mgr *destination)
+/* Emit a SOS marker */
+{
+ int i, td, ta, comps_in_scan;
+ comps_in_scan = 1;
+
+ emit_marker(destination, M_SOS);
+
+ emit_2bytes(destination, 2 * comps_in_scan + 2 + 1 + 3); /* length */
+
+ emit_byte(destination, comps_in_scan);
+
+ for (i = 0; i < comps_in_scan; i++) {
+ /* compptr = cinfo->cur_comp_info[i];*/
+ emit_byte(destination, 1);
+#if 0
+ td = compptr->dc_tbl_no;
+ ta = compptr->ac_tbl_no;
+ if (cinfo->progressive_mode) {
+ /* Progressive mode: only DC or only AC tables are used in one scan;
+ * furthermore, Huffman coding of DC refinement uses no table at all.
+ * We emit 0 for unused field(s); this is recommended by the P&M text
+ * but does not seem to be specified in the standard.
+ */
+ if (cinfo->Ss == 0) {
+ ta = 0; /* DC scan */
+ if (cinfo->Ah != 0 && !cinfo->arith_code)
+ td = 0; /* no DC table either */
+ } else {
+ td = 0; /* AC scan */
+ }
+ }
+ emit_byte(cinfo, (td << 4) + ta);
+#endif
+ emit_byte(destination, 0);
+ }
+
+#if 0
+ emit_byte(cinfo, cinfo->Ss);
+ emit_byte(cinfo, cinfo->Se);
+ emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al);
+#endif
+ emit_byte(destination, 0);
+ emit_byte(destination, 63);
+ emit_byte(destination, 0);
+}
+
+
+static void emit_jfif_app0 (my_destination_mgr *destination)
+/* Emit a JFIF-compliant APP0 marker */
+{
+ /*
+ * Length of APP0 block (2 bytes)
+ * Block ID (4 bytes - ASCII "JFIF")
+ * Zero byte (1 byte to terminate the ID string)
+ * Version Major, Minor (2 bytes - major first)
+ * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)
+ * Xdpu (2 bytes - dots per unit horizontal)
+ * Ydpu (2 bytes - dots per unit vertical)
+ * Thumbnail X size (1 byte)
+ * Thumbnail Y size (1 byte)
+ */
+
+ emit_marker(destination, M_APP0);
+
+ emit_2bytes(destination, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */
+
+ emit_byte(destination, 0x4A); /* Identifier: ASCII "JFIF" */
+ emit_byte(destination, 0x46);
+ emit_byte(destination, 0x49);
+ emit_byte(destination, 0x46);
+ emit_byte(destination, 0);
+ emit_byte(destination, 1); /*destination->JFIF_major_version); / * Version fields */
+ emit_byte(destination, 1); /* destination->JFIF_minor_version); */
+ emit_byte(destination, 1); /* destination->density_unit); / * Pixel size information */
+ emit_2bytes(destination, 0x48); /* (int) destination->X_density); */
+ emit_2bytes(destination, 0x048); /* (int) destination->Y_density); */
+ emit_byte(destination, 0); /* No thumbnail image */
+ emit_byte(destination, 0);
+}
+
+
+#if 0
+/*
+ * These routines allow writing an arbitrary marker with parameters.
+ * The only intended use is to emit COM or APPn markers after calling
+ * write_file_header and before calling write_frame_header.
+ * Other uses are not guaranteed to produce desirable results.
+ * Counting the parameter bytes properly is the caller's responsibility.
+ */
+
+static void write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen)
+/* Emit an arbitrary marker header */
+{
+ if (datalen > (unsigned int) 65533) { /* safety check */
+ perror("Bogus marker length");
+ exit(1);
+ /*ERREXIT(cinfo, JERR_BAD_LENGTH);*/
+ }
+ emit_marker(cinfo, (JPEG_MARKER) marker);
+
+ emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */
+}
+
+static void write_marker_byte (j_compress_ptr cinfo, int val)
+/* Emit one byte of marker parameters following write_marker_header */
+{
+ emit_byte(cinfo, val);
+}
+
+#endif
+
+/*
+ * Write datastream header.
+ * This consists of an SOI and optional APPn markers.
+ * We recommend use of the JFIF marker, but not the Adobe marker,
+ * when using YCbCr or grayscale data. The JFIF marker should NOT
+ * be used for any other JPEG colorspace. The Adobe marker is helpful
+ * to distinguish RGB, CMYK, and YCCK colorspaces.
+ * Note that an application can write additional header markers after
+ * jpeg_start_compress returns.
+ */
+
+static void write_file_header(my_destination_mgr *destination) {
+
+ emit_marker(destination, M_SOI); /* first the SOI */
+
+ /* SOI is defined to reset restart interval to 0 */
+
+ emit_jfif_app0(destination);
+}
+
+/*
+ * Write frame header.
+ * This consists of DQT and SOFn markers.
+ * Note that we do not emit the SOF until we have emitted the DQT(s).
+ * This avoids compatibility problems with incorrect implementations that
+ * try to error-check the quant table numbers as soon as they see the SOF.
+ */
+
+static void write_frame_header(my_destination_mgr *destination, int x, int y) {
+ int ci, prec;
+ boolean is_baseline;
+ jpeg_component_info *compptr;
+#if 0
+ /* Emit DQT for each quantization table.
+ * Note that emit_dqt() suppresses any duplicate tables.
+ */
+ prec = 0;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+ }
+ /* now prec is nonzero iff there are any 16-bit quant tables. */
+
+ /* Check for a non-baseline specification.
+ * Note we assume that Huffman table numbers won't be changed later.
+ */
+ if (cinfo->arith_code || cinfo->progressive_mode ||
+ cinfo->data_precision != 8) {
+ is_baseline = FALSE;
+ } else {
+ is_baseline = TRUE;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1)
+ is_baseline = FALSE;
+ }
+ if (prec && is_baseline) {
+ is_baseline = FALSE;
+ /* If it's baseline except for quantizer size, warn the user */
+ printf("Caution: quantization tables are too coarse for baseline JPEG");
+ }
+ }
+
+ /* Emit the proper SOF marker */
+ if (cinfo->arith_code) {
+ emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */
+ } else {
+ if (cinfo->progressive_mode)
+ emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */
+ else if (is_baseline)
+ emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */
+ else
+ emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */
+ }
+#endif
+ emit_dqt(destination, 0);
+ emit_sof(destination, M_SOF0, x, y);
+}
+
+
+/*
+ * Write scan header.
+ * This consists of DHT or DAC markers, optional DRI, and SOS.
+ * Compressed data will be written following the SOS.
+ */
+
+static void write_scan_header(my_destination_mgr *destination)
+{
+ int i;
+ int comps_in_scan = 1;
+
+
+ /* Emit Huffman tables.
+ * Note that emit_dht() suppresses any duplicate tables.
+ */
+ for (i = 0; i < comps_in_scan; i++) {
+#if 0
+ if (cinfo->progressive_mode) {
+ /* Progressive mode: only DC or only AC tables are used in one scan */
+ if (cinfo->Ss == 0) {
+ if (cinfo->Ah == 0) /* DC needs no table for refinement scan */
+ emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
+ } else {
+ emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
+ }
+ } else {
+ /* Sequential mode: need both DC and AC tables */
+ emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
+ emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
+ }
+#endif
+ emit_dht(destination, 0, FALSE);
+ emit_dht(destination, 1, TRUE);
+ }
+
+ emit_sos(destination);
+}
+
+/*
+ * Write datastream trailer.
+ */
+
+static void write_file_trailer(my_destination_mgr *destination) {
+ emit_marker(destination, M_EOI);
+}
+
+#if 0
+/*
+ * Write an abbreviated table-specification datastream.
+ * This consists of SOI, DQT and DHT tables, and EOI.
+ * Any table that is defined and not marked sent_table = TRUE will be
+ * emitted. Note that all tables will be marked sent_table = TRUE at exit.
+ */
+
+static void write_tables_only (j_compress_ptr cinfo)
+{
+ int i;
+
+ emit_marker(cinfo, M_SOI);
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ if (cinfo->quant_tbl_ptrs[i] != NULL)
+ (void) emit_dqt(cinfo, i);
+ }
+
+ if (! cinfo->arith_code) {
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ if (cinfo->dc_huff_tbl_ptrs[i] != NULL)
+ emit_dht(cinfo, i, FALSE);
+ if (cinfo->ac_huff_tbl_ptrs[i] != NULL)
+ emit_dht(cinfo, i, TRUE);
+ }
+ }
+
+ emit_marker(cinfo, M_EOI);
+}
+
+
+/*
+ * Initialize the marker writer module.
+ */
+#if 0
+void jinit_marker_writer (j_compress_ptr cinfo) {
+ my_marker_ptr marker;
+
+ /* Create the subobject */
+ marker = (my_marker_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_marker_writer));
+ cinfo->marker = (struct jpeg_marker_writer *) marker;
+ /* Initialize method pointers */
+ marker->pub.write_file_header = write_file_header;
+ marker->pub.write_frame_header = write_frame_header;
+ marker->pub.write_scan_header = write_scan_header;
+ marker->pub.write_file_trailer = write_file_trailer;
+ marker->pub.write_tables_only = write_tables_only;
+ marker->pub.write_marker_header = write_marker_header;
+ marker->pub.write_marker_byte = write_marker_byte;
+ /* Initialize private state */
+ marker->last_restart_interval = 0;
+}
+#endif
+
+int main(void) {
+ int retval;
+ my_destination_mgr destination;
+ size_t datacount;
+
+ retval = 0;
+
+ /* Initialize destination structure */
+ destination.pub.next_output_byte = destination.buffer;
+ destination.pub.free_in_buffer = OUTPUT_BUF_SIZE;
+ destination.outfile = fopen("outfile.jpg", "w+");
+
+ /* do something usefull here */
+ printf("Output\n");
+ write_file_header(&destination);
+ write_frame_header(&destination, 640, 480);
+ write_scan_header(&destination);
+ /* write image here */
+ emit_byte(&destination, 0xa6);
+ emit_byte(&destination, 0x17);
+ emit_byte(&destination, 0x11);
+ emit_byte(&destination, 0x83);
+ emit_byte(&destination, 0xff);
+ emit_byte(&destination, 0x0);
+ emit_byte(&destination, 0x4c);
+ emit_byte(&destination, 0x43);
+ emit_byte(&destination, 0x7f);
+ emit_byte(&destination, 0xe4);
+ emit_byte(&destination, 0xce);
+ emit_byte(&destination, 0x6b);
+
+ /* finish up */
+ write_file_trailer(&destination);
+
+ /* Terminate destination structure */
+ datacount = OUTPUT_BUF_SIZE - destination.pub.free_in_buffer;
+ if (datacount > 0) {
+ if (fwrite(destination.buffer, 1, datacount, destination.outfile) != datacount) {
+ perror("Output file write error --- out of disk space?");
+ exit(1);
+ }
+ }
+ fflush(destination.outfile);
+ if (ferror(destination.outfile)) {
+ perror("Output file write error --- out of disk space?");
+ exit(1);
+ }
+ fclose(destination.outfile);
+
+ return retval;
+}
+#endif