axon 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.gemtest +0 -0
  2. data/CHANGELOG.rdoc +3 -0
  3. data/README.rdoc +104 -0
  4. data/Rakefile +30 -0
  5. data/TODO.rdoc +12 -0
  6. data/ext/axon/axon.c +20 -0
  7. data/ext/axon/bilinear_interpolation.c +115 -0
  8. data/ext/axon/extconf.rb +21 -0
  9. data/ext/axon/iccjpeg.c +248 -0
  10. data/ext/axon/iccjpeg.h +73 -0
  11. data/ext/axon/interpolation.h +7 -0
  12. data/ext/axon/jpeg_common.c +118 -0
  13. data/ext/axon/jpeg_common.h +37 -0
  14. data/ext/axon/jpeg_native_writer.c +248 -0
  15. data/ext/axon/jpeg_reader.c +774 -0
  16. data/ext/axon/nearest_neighbor_interpolation.c +50 -0
  17. data/ext/axon/png_common.c +21 -0
  18. data/ext/axon/png_common.h +18 -0
  19. data/ext/axon/png_native_writer.c +166 -0
  20. data/ext/axon/png_reader.c +381 -0
  21. data/lib/axon/axon.so +0 -0
  22. data/lib/axon/bilinear_scaler.rb +60 -0
  23. data/lib/axon/cropper.rb +35 -0
  24. data/lib/axon/fit.rb +67 -0
  25. data/lib/axon/jpeg_writer.rb +41 -0
  26. data/lib/axon/nearest_neighbor_scaler.rb +39 -0
  27. data/lib/axon/png_writer.rb +35 -0
  28. data/lib/axon/scaler.rb +41 -0
  29. data/lib/axon/solid.rb +23 -0
  30. data/lib/axon.rb +45 -0
  31. data/test/_test_readme.rb +34 -0
  32. data/test/helper.rb +17 -0
  33. data/test/reader_tests.rb +115 -0
  34. data/test/stress_tests.rb +71 -0
  35. data/test/test_bilinear_scaler.rb +9 -0
  36. data/test/test_cropper.rb +9 -0
  37. data/test/test_exif.rb +39 -0
  38. data/test/test_generator.rb +10 -0
  39. data/test/test_icc.rb +18 -0
  40. data/test/test_jpeg.rb +9 -0
  41. data/test/test_jpeg_reader.rb +109 -0
  42. data/test/test_jpeg_writer.rb +26 -0
  43. data/test/test_nearest_neighbor_scaler.rb +13 -0
  44. data/test/test_png.rb +9 -0
  45. data/test/test_png_reader.rb +15 -0
  46. data/test/test_png_writer.rb +13 -0
  47. data/test/writer_tests.rb +179 -0
  48. metadata +148 -0
data/.gemtest ADDED
File without changes
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ === 0.0.1 / 2011-08-01
2
+
3
+ * Initial Release
data/README.rdoc ADDED
@@ -0,0 +1,104 @@
1
+ = Axon
2
+
3
+ http://github.com/ender672/axon
4
+
5
+ == DESCRIPTION:
6
+
7
+ Axon is a library for streaming and manipulating JPEG and PNG images. It scales
8
+ and crops images along the way.
9
+
10
+ By limiting its functionality, Axon is able to depend on two ubiquitous
11
+ libraries: libjpeg and libpng. Axon can be installed anywhere those libraries
12
+ are available.
13
+
14
+ Axon never stores an entire image in memory. All images and operations are
15
+ streamed from an input to an output. As a result, memory requirements and
16
+ latency are low.
17
+
18
+ == FEATURES:
19
+
20
+ * Read and Write JPEG and PNG images.
21
+ * Scale images using bilinear (fast!) or nearest-neighbor (even faster!)
22
+ interpolation.
23
+ * Crop images.
24
+
25
+ == SYNOPSIS:
26
+
27
+ # Short, chained example. Reads a JPEG from io_in and writes scaled png to
28
+ # io_out.
29
+ Axon.JPEG(io_in).fit(100, 100).write_png(io_out)
30
+
31
+ # Longer example, reads the JPEG header, looks at properties and header
32
+ # values, sets decompression options, scales the image, sets compression
33
+ # options, and writes a JPEG.
34
+ image = Axon.JPEG(io, [:APP2])
35
+
36
+ puts image.width
37
+ puts image.height
38
+ puts image[:APP2]
39
+ image.scale_denom = 4
40
+
41
+ jpeg = image.fit(100, 100).to_jpeg
42
+ jpeg.quality = 88
43
+ jpeg.write(io)
44
+
45
+ == BASIC API:
46
+
47
+ There are three basic object types: Image, Reader and Writer.
48
+
49
+ Every Image object has the following methods:
50
+
51
+ * Image#height, Image#width
52
+ These are the output dimensions of the image.
53
+ * Image#color_model
54
+ Can be :GRAYSCALE or :RGB
55
+ * Image#components
56
+ An RGB image will have 3 components. A grayscale image with an alpha channel
57
+ (transparency) will have 2 components: grayscale and transparency, etc.
58
+ * Image#each(&block)
59
+ Yields every line in the image as a binary ruby string. Image properties
60
+ are not allowed to change between the first and last yield.
61
+
62
+ A Reader object has the same methods as an Image object, with added methods that
63
+ are specific to the decoding of the image format.
64
+
65
+ A Writer has two methods:
66
+
67
+ * Writer#write(io[, options])
68
+ * Writer#data([options]) # returns image data as a string
69
+
70
+ == REQUIREMENTS:
71
+
72
+ IJG JPEG Library Version 6b or later.
73
+ pnglib version 1.2.x or later.
74
+
75
+ == INSTALL:
76
+
77
+ gem install axon
78
+
79
+ == LICENSE:
80
+
81
+ (The MIT License)
82
+
83
+ Copyright (c) 2011
84
+
85
+ * {Timothy Elliott}[http://holymonkey.com]
86
+
87
+ Permission is hereby granted, free of charge, to any person obtaining
88
+ a copy of this software and associated documentation files (the
89
+ 'Software'), to deal in the Software without restriction, including
90
+ without limitation the rights to use, copy, modify, merge, publish,
91
+ distribute, sublicense, and/or sell copies of the Software, and to
92
+ permit persons to whom the Software is furnished to do so, subject to
93
+ the following conditions:
94
+
95
+ The above copyright notice and this permission notice shall be
96
+ included in all copies or substantial portions of the Software.
97
+
98
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
99
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
100
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
101
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
102
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
103
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
104
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+
4
+ HOE = Hoe.spec 'axon' do
5
+ developer('Timothy Elliott', 'tle@holymonkey.com')
6
+ self.readme_file = 'README.rdoc'
7
+ self.history_file = 'CHANGELOG.rdoc'
8
+ self.extra_dev_deps << ['rake-compiler', '>= 0']
9
+ self.spec_extras = { :extensions => ["ext/axon/extconf.rb"] }
10
+ end
11
+
12
+ require "rake/extensiontask"
13
+
14
+ Rake::ExtensionTask.new('axon', HOE.spec) do |ext|
15
+ ext.lib_dir = File.join('lib', 'axon')
16
+ end
17
+
18
+ Rake::Task[:test].prerequisites << :compile
19
+
20
+ desc 'Run a test in looped mode so that you can look for memory leaks.'
21
+ task 'test_loop' do
22
+ code = %Q[require '#{$*[1]}'; loop{ MiniTest::Unit.new.run }]
23
+ cmd = %Q[ruby -Ilib -Itest -e "#{ code }"]
24
+ system cmd
25
+ end
26
+
27
+ desc 'Watch Memory use of a looping test'
28
+ task 'test_loop_mem' do
29
+ system 'watch "ps aux | grep Itest"'
30
+ end
data/TODO.rdoc ADDED
@@ -0,0 +1,12 @@
1
+ = TODO
2
+ * have a setting where decode / encode warnings will result in exceptions
3
+
4
+ * Test scalers with images that lie about width & height. Never trust
5
+ Image#width or Image#height -- instead always go by scanline size and how
6
+ many times #each_scanline calls yield
7
+
8
+ * add #initialize_copy
9
+
10
+ * Check frozen status on setters, etc.
11
+ * Check frozen status (and freeze) on all VALUEs that we stash for later use
12
+ * Check trusted status (1.9.x only)
data/ext/axon/axon.c ADDED
@@ -0,0 +1,20 @@
1
+ #include <ruby.h>
2
+
3
+ #include "jpeg_common.h"
4
+ #include "png_common.h"
5
+ #include "interpolation.h"
6
+
7
+ void
8
+ Init_axon()
9
+ {
10
+ Init_jpeg();
11
+ Init_jpeg_reader();
12
+ Init_jpeg_native_writer();
13
+
14
+ Init_png();
15
+ Init_png_reader();
16
+ Init_png_native_writer();
17
+
18
+ Init_bilinear_interpolation();
19
+ Init_nearest_neighbor_interpolation();
20
+ }
@@ -0,0 +1,115 @@
1
+ #include <ruby.h>
2
+
3
+ static ID id_image, id_components, id_width_ratio, id_width;
4
+
5
+
6
+ /* c00 a c10
7
+ * --------------------------
8
+ * | | |
9
+ * | | |
10
+ * | ty| |
11
+ * | tx | |
12
+ * |------------------+-----|
13
+ * | /| |
14
+ * | sample| |
15
+ * | | |
16
+ * | | |
17
+ * | | |
18
+ * | | |
19
+ * --------------------------
20
+ * c01 b c11
21
+ *
22
+ * a = (1 - tx) * c00 + tx * c10
23
+ * b = (1 - tx) * c01 + tx * c11
24
+ * sample = (1 - ty) * a + ty * b
25
+ *
26
+ * sample = (1 - ty) * (1 - tx) * c00 +
27
+ * (1 - ty) * tx * c10 +
28
+ * ty * (1 - tx) * c01 +
29
+ ty * tx * c11
30
+ */
31
+ static VALUE
32
+ interpolate_scanline2(size_t width, double width_ratio, size_t components,
33
+ double ty, char *scanline1, char *scanline2)
34
+ {
35
+ VALUE rb_dest_sl;
36
+ double sample_x, tx, _tx, p00, p10, p01, p11;
37
+ unsigned char *c00, *c10, *c01, *c11, *dest_sl;
38
+ size_t sample_x_i, i, j;
39
+
40
+ rb_dest_sl = rb_str_new(0, width * components);
41
+ dest_sl = RSTRING_PTR(rb_dest_sl);
42
+
43
+ for (i = 0; i < width; i++) {
44
+ sample_x = i / width_ratio;
45
+ sample_x_i = (int)sample_x;
46
+
47
+ tx = sample_x - sample_x_i;
48
+ _tx = 1 - tx;
49
+
50
+ p11 = tx * ty;
51
+ p01 = _tx * ty;
52
+ p10 = tx - p11;
53
+ p00 = _tx - p01;
54
+
55
+ c00 = scanline1 + sample_x_i * components;
56
+ c10 = c00 + components;
57
+ c01 = scanline2 + sample_x_i * components;
58
+ c11 = c01 + components;
59
+
60
+ for (j = 0; j < components; j++)
61
+ *dest_sl++ = p00 * c00[j] + p10 * c10[j] + p01 * c01[j] +
62
+ p11 * c11[j];
63
+ }
64
+
65
+ return rb_dest_sl;
66
+ }
67
+
68
+ /*
69
+ * call-seq:
70
+ * image.interpolate_scanline(original_scanlines, q) -> interpolated_scanline
71
+ * Expects the instance variable @image to respond to components, and
72
+ * expects the intance variable @width_ratio to respond to the ratio that
73
+ * we will resample our width to.
74
+ */
75
+ static VALUE
76
+ interpolate_scanline(VALUE self, VALUE orig_scanline1, VALUE orig_scanline2,
77
+ VALUE rb_sample_y)
78
+ {
79
+ VALUE rb_components, rb_width_ratio, rb_image, rb_width;
80
+ double width_ratio, ty, sample_y;
81
+ unsigned char *scanline1, *scanline2;
82
+ size_t width, components;
83
+
84
+ rb_width = rb_ivar_get(self, id_width);
85
+ width = FIX2INT(rb_width);
86
+
87
+ rb_image = rb_ivar_get(self, id_image);
88
+ rb_components = rb_funcall(rb_image, id_components, 0);
89
+ components = FIX2INT(rb_components);
90
+
91
+ rb_width_ratio = rb_ivar_get(self, id_width_ratio);
92
+ width_ratio = NUM2DBL(rb_width_ratio);
93
+
94
+ sample_y = NUM2DBL(rb_sample_y);
95
+ ty = sample_y - (int)sample_y;
96
+
97
+ scanline1 = RSTRING_PTR(orig_scanline1);
98
+ scanline2 = RSTRING_PTR(orig_scanline2);
99
+
100
+ return interpolate_scanline2(width, width_ratio, components, ty, scanline1,
101
+ scanline2);
102
+ }
103
+
104
+ void
105
+ Init_bilinear_interpolation()
106
+ {
107
+ VALUE mAxon = rb_define_module("Axon");
108
+ VALUE mBilinearScaling = rb_define_module_under(mAxon, "BilinearScaling");
109
+ rb_define_method(mBilinearScaling, "interpolate_scanline", interpolate_scanline, 3);
110
+
111
+ id_width = rb_intern("@width");
112
+ id_width_ratio = rb_intern("@width_ratio");
113
+ id_image = rb_intern("@image");
114
+ id_components = rb_intern("components");
115
+ }
@@ -0,0 +1,21 @@
1
+ require 'mkmf'
2
+
3
+ $CFLAGS += " -g -O0" if ENV['GCC_DEBUG']
4
+
5
+ unless find_header('jpeglib.h')
6
+ abort "libjpeg headers are missing. Please install libjpeg headers."
7
+ end
8
+
9
+ unless have_library('jpeg', nil)
10
+ abort "libjpeg is missing. Please install libjpeg."
11
+ end
12
+
13
+ unless find_header('png.h')
14
+ abort "libpng headers are missing. Please install libpng headers."
15
+ end
16
+
17
+ unless have_library('png', nil)
18
+ abort "libpng is missing. Please install libpng."
19
+ end
20
+
21
+ create_makefile('jpeg/axon')
@@ -0,0 +1,248 @@
1
+ /*
2
+ * iccprofile.c
3
+ *
4
+ * This file provides code to read and write International Color Consortium
5
+ * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has
6
+ * defined a standard format for including such data in JPEG "APP2" markers.
7
+ * The code given here does not know anything about the internal structure
8
+ * of the ICC profile data; it just knows how to put the profile data into
9
+ * a JPEG file being written, or get it back out when reading.
10
+ *
11
+ * This code depends on new features added to the IJG JPEG library as of
12
+ * IJG release 6b; it will not compile or work with older IJG versions.
13
+ *
14
+ * NOTE: this code would need surgery to work on 16-bit-int machines
15
+ * with ICC profiles exceeding 64K bytes in size. If you need to do that,
16
+ * change all the "unsigned int" variables to "INT32". You'll also need
17
+ * to find a malloc() replacement that can allocate more than 64K.
18
+ */
19
+
20
+ #include "iccjpeg.h"
21
+ #include <stdlib.h> /* define malloc() */
22
+
23
+
24
+ /*
25
+ * Since an ICC profile can be larger than the maximum size of a JPEG marker
26
+ * (64K), we need provisions to split it into multiple markers. The format
27
+ * defined by the ICC specifies one or more APP2 markers containing the
28
+ * following data:
29
+ * Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
30
+ * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte)
31
+ * Number of markers Total number of APP2's used (1 byte)
32
+ * Profile data (remainder of APP2 data)
33
+ * Decoders should use the marker sequence numbers to reassemble the profile,
34
+ * rather than assuming that the APP2 markers appear in the correct sequence.
35
+ */
36
+
37
+ #define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
38
+ #define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
39
+ #define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
40
+ #define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
41
+
42
+
43
+ /*
44
+ * This routine writes the given ICC profile data into a JPEG file.
45
+ * It *must* be called AFTER calling jpeg_start_compress() and BEFORE
46
+ * the first call to jpeg_write_scanlines().
47
+ * (This ordering ensures that the APP2 marker(s) will appear after the
48
+ * SOI and JFIF or Adobe markers, but before all else.)
49
+ */
50
+
51
+ void
52
+ write_icc_profile (j_compress_ptr cinfo,
53
+ const JOCTET *icc_data_ptr,
54
+ unsigned int icc_data_len)
55
+ {
56
+ unsigned int num_markers; /* total number of markers we'll write */
57
+ int cur_marker = 1; /* per spec, counting starts at 1 */
58
+ unsigned int length; /* number of bytes to write in this marker */
59
+
60
+ /* Calculate the number of markers we'll need, rounding up of course */
61
+ num_markers = icc_data_len / MAX_DATA_BYTES_IN_MARKER;
62
+ if (num_markers * MAX_DATA_BYTES_IN_MARKER != icc_data_len)
63
+ num_markers++;
64
+
65
+ while (icc_data_len > 0) {
66
+ /* length of profile to put in this marker */
67
+ length = icc_data_len;
68
+ if (length > MAX_DATA_BYTES_IN_MARKER)
69
+ length = MAX_DATA_BYTES_IN_MARKER;
70
+ icc_data_len -= length;
71
+
72
+ /* Write the JPEG marker header (APP2 code and marker length) */
73
+ jpeg_write_m_header(cinfo, ICC_MARKER,
74
+ (unsigned int) (length + ICC_OVERHEAD_LEN));
75
+
76
+ /* Write the marker identifying string "ICC_PROFILE" (null-terminated).
77
+ * We code it in this less-than-transparent way so that the code works
78
+ * even if the local character set is not ASCII.
79
+ */
80
+ jpeg_write_m_byte(cinfo, 0x49);
81
+ jpeg_write_m_byte(cinfo, 0x43);
82
+ jpeg_write_m_byte(cinfo, 0x43);
83
+ jpeg_write_m_byte(cinfo, 0x5F);
84
+ jpeg_write_m_byte(cinfo, 0x50);
85
+ jpeg_write_m_byte(cinfo, 0x52);
86
+ jpeg_write_m_byte(cinfo, 0x4F);
87
+ jpeg_write_m_byte(cinfo, 0x46);
88
+ jpeg_write_m_byte(cinfo, 0x49);
89
+ jpeg_write_m_byte(cinfo, 0x4C);
90
+ jpeg_write_m_byte(cinfo, 0x45);
91
+ jpeg_write_m_byte(cinfo, 0x0);
92
+
93
+ /* Add the sequencing info */
94
+ jpeg_write_m_byte(cinfo, cur_marker);
95
+ jpeg_write_m_byte(cinfo, (int) num_markers);
96
+
97
+ /* Add the profile data */
98
+ while (length--) {
99
+ jpeg_write_m_byte(cinfo, *icc_data_ptr);
100
+ icc_data_ptr++;
101
+ }
102
+ cur_marker++;
103
+ }
104
+ }
105
+
106
+
107
+ /*
108
+ * Prepare for reading an ICC profile
109
+ */
110
+
111
+ void
112
+ setup_read_icc_profile (j_decompress_ptr cinfo)
113
+ {
114
+ /* Tell the library to keep any APP2 data it may find */
115
+ jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
116
+ }
117
+
118
+
119
+ /*
120
+ * Handy subroutine to test whether a saved marker is an ICC profile marker.
121
+ */
122
+
123
+ static boolean
124
+ marker_is_icc (jpeg_saved_marker_ptr marker)
125
+ {
126
+ return
127
+ marker->marker == ICC_MARKER &&
128
+ marker->data_length >= ICC_OVERHEAD_LEN &&
129
+ /* verify the identifying string */
130
+ GETJOCTET(marker->data[0]) == 0x49 &&
131
+ GETJOCTET(marker->data[1]) == 0x43 &&
132
+ GETJOCTET(marker->data[2]) == 0x43 &&
133
+ GETJOCTET(marker->data[3]) == 0x5F &&
134
+ GETJOCTET(marker->data[4]) == 0x50 &&
135
+ GETJOCTET(marker->data[5]) == 0x52 &&
136
+ GETJOCTET(marker->data[6]) == 0x4F &&
137
+ GETJOCTET(marker->data[7]) == 0x46 &&
138
+ GETJOCTET(marker->data[8]) == 0x49 &&
139
+ GETJOCTET(marker->data[9]) == 0x4C &&
140
+ GETJOCTET(marker->data[10]) == 0x45 &&
141
+ GETJOCTET(marker->data[11]) == 0x0;
142
+ }
143
+
144
+
145
+ /*
146
+ * See if there was an ICC profile in the JPEG file being read;
147
+ * if so, reassemble and return the profile data.
148
+ *
149
+ * TRUE is returned if an ICC profile was found, FALSE if not.
150
+ * If TRUE is returned, *icc_data_ptr is set to point to the
151
+ * returned data, and *icc_data_len is set to its length.
152
+ *
153
+ * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
154
+ * and must be freed by the caller with free() when the caller no longer
155
+ * needs it. (Alternatively, we could write this routine to use the
156
+ * IJG library's memory allocator, so that the data would be freed implicitly
157
+ * at jpeg_finish_decompress() time. But it seems likely that many apps
158
+ * will prefer to have the data stick around after decompression finishes.)
159
+ *
160
+ * NOTE: if the file contains invalid ICC APP2 markers, we just silently
161
+ * return FALSE. You might want to issue an error message instead.
162
+ */
163
+
164
+ boolean
165
+ read_icc_profile (j_decompress_ptr cinfo,
166
+ JOCTET **icc_data_ptr,
167
+ unsigned int *icc_data_len)
168
+ {
169
+ jpeg_saved_marker_ptr marker;
170
+ int num_markers = 0;
171
+ int seq_no;
172
+ JOCTET *icc_data;
173
+ unsigned int total_length;
174
+ #define MAX_SEQ_NO 255 /* sufficient since marker numbers are bytes */
175
+ char marker_present[MAX_SEQ_NO+1]; /* 1 if marker found */
176
+ unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */
177
+ unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */
178
+
179
+ *icc_data_ptr = NULL; /* avoid confusion if FALSE return */
180
+ *icc_data_len = 0;
181
+
182
+ /* This first pass over the saved markers discovers whether there are
183
+ * any ICC markers and verifies the consistency of the marker numbering.
184
+ */
185
+
186
+ for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
187
+ marker_present[seq_no] = 0;
188
+
189
+ for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
190
+ if (marker_is_icc(marker)) {
191
+ if (num_markers == 0)
192
+ num_markers = GETJOCTET(marker->data[13]);
193
+ else if (num_markers != GETJOCTET(marker->data[13]))
194
+ return FALSE; /* inconsistent num_markers fields */
195
+ seq_no = GETJOCTET(marker->data[12]);
196
+ if (seq_no <= 0 || seq_no > num_markers)
197
+ return FALSE; /* bogus sequence number */
198
+ if (marker_present[seq_no])
199
+ return FALSE; /* duplicate sequence numbers */
200
+ marker_present[seq_no] = 1;
201
+ data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
202
+ }
203
+ }
204
+
205
+ if (num_markers == 0)
206
+ return FALSE;
207
+
208
+ /* Check for missing markers, count total space needed,
209
+ * compute offset of each marker's part of the data.
210
+ */
211
+
212
+ total_length = 0;
213
+ for (seq_no = 1; seq_no <= num_markers; seq_no++) {
214
+ if (marker_present[seq_no] == 0)
215
+ return FALSE; /* missing sequence number */
216
+ data_offset[seq_no] = total_length;
217
+ total_length += data_length[seq_no];
218
+ }
219
+
220
+ if (total_length <= 0)
221
+ return FALSE; /* found only empty markers? */
222
+
223
+ /* Allocate space for assembled data */
224
+ icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
225
+ if (icc_data == NULL)
226
+ return FALSE; /* oops, out of memory */
227
+
228
+ /* and fill it in */
229
+ for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
230
+ if (marker_is_icc(marker)) {
231
+ JOCTET FAR *src_ptr;
232
+ JOCTET *dst_ptr;
233
+ unsigned int length;
234
+ seq_no = GETJOCTET(marker->data[12]);
235
+ dst_ptr = icc_data + data_offset[seq_no];
236
+ src_ptr = marker->data + ICC_OVERHEAD_LEN;
237
+ length = data_length[seq_no];
238
+ while (length--) {
239
+ *dst_ptr++ = *src_ptr++;
240
+ }
241
+ }
242
+ }
243
+
244
+ *icc_data_ptr = icc_data;
245
+ *icc_data_len = total_length;
246
+
247
+ return TRUE;
248
+ }
@@ -0,0 +1,73 @@
1
+ /*
2
+ * iccprofile.h
3
+ *
4
+ * This file provides code to read and write International Color Consortium
5
+ * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has
6
+ * defined a standard format for including such data in JPEG "APP2" markers.
7
+ * The code given here does not know anything about the internal structure
8
+ * of the ICC profile data; it just knows how to put the profile data into
9
+ * a JPEG file being written, or get it back out when reading.
10
+ *
11
+ * This code depends on new features added to the IJG JPEG library as of
12
+ * IJG release 6b; it will not compile or work with older IJG versions.
13
+ *
14
+ * NOTE: this code would need surgery to work on 16-bit-int machines
15
+ * with ICC profiles exceeding 64K bytes in size. See iccprofile.c
16
+ * for details.
17
+ */
18
+
19
+ #include <stdio.h> /* needed to define "FILE", "NULL" */
20
+ #include "jpeglib.h"
21
+
22
+
23
+ /*
24
+ * This routine writes the given ICC profile data into a JPEG file.
25
+ * It *must* be called AFTER calling jpeg_start_compress() and BEFORE
26
+ * the first call to jpeg_write_scanlines().
27
+ * (This ordering ensures that the APP2 marker(s) will appear after the
28
+ * SOI and JFIF or Adobe markers, but before all else.)
29
+ */
30
+
31
+ extern void write_icc_profile JPP((j_compress_ptr cinfo,
32
+ const JOCTET *icc_data_ptr,
33
+ unsigned int icc_data_len));
34
+
35
+
36
+ /*
37
+ * Reading a JPEG file that may contain an ICC profile requires two steps:
38
+ *
39
+ * 1. After jpeg_create_decompress() but before jpeg_read_header(),
40
+ * call setup_read_icc_profile(). This routine tells the IJG library
41
+ * to save in memory any APP2 markers it may find in the file.
42
+ *
43
+ * 2. After jpeg_read_header(), call read_icc_profile() to find out
44
+ * whether there was a profile and obtain it if so.
45
+ */
46
+
47
+
48
+ /*
49
+ * Prepare for reading an ICC profile
50
+ */
51
+
52
+ extern void setup_read_icc_profile JPP((j_decompress_ptr cinfo));
53
+
54
+
55
+ /*
56
+ * See if there was an ICC profile in the JPEG file being read;
57
+ * if so, reassemble and return the profile data.
58
+ *
59
+ * TRUE is returned if an ICC profile was found, FALSE if not.
60
+ * If TRUE is returned, *icc_data_ptr is set to point to the
61
+ * returned data, and *icc_data_len is set to its length.
62
+ *
63
+ * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
64
+ * and must be freed by the caller with free() when the caller no longer
65
+ * needs it. (Alternatively, we could write this routine to use the
66
+ * IJG library's memory allocator, so that the data would be freed implicitly
67
+ * at jpeg_finish_decompress() time. But it seems likely that many apps
68
+ * will prefer to have the data stick around after decompression finishes.)
69
+ */
70
+
71
+ extern boolean read_icc_profile JPP((j_decompress_ptr cinfo,
72
+ JOCTET **icc_data_ptr,
73
+ unsigned int *icc_data_len));
@@ -0,0 +1,7 @@
1
+ #ifndef AXON_INTERPOLATION_H
2
+ #define AXON_INTERPOLATION_H
3
+
4
+ void Init_bilinear_interpolation();
5
+ void Init_nearest_neighbor_interpolation();
6
+
7
+ #endif