axon 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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