1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
|
<!doctype HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<meta http-equiv="Content-Language" content="en-us">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Storage Guide</title>
<link rel="stylesheet" type="text/css" href="../style.css">
</head>
<body>
<h1>Storage Guide</h1>
<h3 align="left"><a name="read">Reading</a></h3>
<p>When reading the file extension is not relevant to determine the file
format, but it is used to speed up the process of finding the correct format.
With few exceptions the format drivers that access multiple images can read
them in any sequence you want. </p>
<p>During the read process the original data can be converted to some options
of user data. Not all conversions are available. You can convert any data to a
bitmap version of it, and you can select any of the color mode flags<b>
IM_ALPHA</b>, <b>IM_PACKED</b> and <b>IM_TOPDOWN</b>,
regardless of the file original configuration.</p>
<p>Remember that even if all the images in the file have the same parameters
you still have to call <b>imFileReadImageInfo</b> before calling <b>imFileReadImageData</b>. </p>
<p>In the following example all the images in the file are loaded.</p>
<pre>char format[10], compression[10];
int error, image_count;
int width, height, color_mode, data_type;
void* data;
imFile* ifile = imFileOpen("test.tif", &error);
if (error != IM_ERR_NONE)
// handle the error
imFileGetInfo(ifile, format, compression, &image_count);
for (i = 0; i < image_count, i++)
{
error = imFileReadImageInfo(ifile, i, &width, &height, &color_mode, &data_type);
if (error != IM_ERR_NONE)
// handle the error
// prepare data
error = imFileReadImageData(ifile, data, 0, -1); // no bitmap convertion, use original color mode flags
if (error != IM_ERR_NONE)
// handle the error
// store data somewhere
}
imFileClose(ifile); </pre>
<p>A more simple code loads only the first image in the file:</p>
<pre>imFile* ifile = imFileOpen(file_name, &error);
imFileReadImageInfo(ifile, 0, &width, &height, &color_mode, &data_type);
imFileReadImageData(ifile, data, 0, -1);
imFileClose(ifile); </pre>
<p>If you are using the <b>imImage</b> structure it is easier:</p>
<pre>imFile* ifile = imFileOpen(file_name, &error);
imImage* image = imFileLoadImage(ifile, 0, &error);</pre>
<pre>// or use imFileLoadBitmap to force a bitmap conversion
imFileClose(ifile);</pre>
<p>Or the simplest version:</p>
<pre>imImage* image = imFileImageLoad(file_name, 0, &error);</pre>
<h3 align="left"><a name="write">Writing</a></h3>
<p>When writing there is no color space or data type conversion. Only color
mode flags can be different: <b>IM_ALPHA</b>, <b>IM_PACKED</b> and
<b>IM_TOPDOWN</b>. You just have to describe your data and the <b>imFileWriteImageData</b> will handle the color mode flag differences.</p>
<p>Of course you still have to check the error codes because, not all color
spaces and data types are supported by each format.</p>
<p>When saving a sequence of images you must provide each image in the order
that they will be in the file. For a video or animation start from frame 0 and
go on, you can not jump or change the frame order. Also when saving videos you
should not forget to save the numbers of frames per second in the attribute
"FPS", the default value is 15.</p>
<p>For all the formats it is not necessary to set the compression, each driver
will choose a default compression. But you may set it using the function <b>imFileSetInfo</b>.</p>
<p>To save several images to the same file:</p>
<pre>int error, width, height;
void *data;
imFile* ifile = imFileNew("test.tif", "TIFF", &error);
if (error != IM_ERR_NONE)
// handle the error
for (i = 0; i < image_count, i++)
{
error = imFileWriteImageInfo(ifile, width, height, IM_RGB, IM_BYTE);
if (error != IM_ERR_NONE)
// handle the error
error = imFileWriteImageData(ifile, data);
if (error != IM_ERR_NONE)
// handle the error
}
imFileClose(ifile); </pre>
<p>But remember that not all file formats supports several images. To save
just one image is more simple:</p>
<pre>imFile* ifile = imFileNew(file_name, format, &error);
error = imFileWriteImageInfo(ifile, width, height, color_mode, data_type);
error = imFileWriteImageData(ifile, data);
imFileClose(ifile); </pre>
<p>If you are using the <b>imImage</b> structure it is easier:</p>
<pre>imFile* ifile = imFileNew(file_name, format, &error);
error = imFileSaveImage(ifile, image);
imFileClose(ifile);</pre>
<p>Or the simplest version:</p>
<pre>error = imFileImageSave(file_name, format, image);</pre>
<h3>Error Messages</h3>
<p>Here is a sample error message display using IUP and IM error codes:</p>
<pre>static void imIupErrorMessage(int error, int interactive)
{
char* lang = IupGetLanguage();
char *msg, *title;
if (strcmp(lang, "ENGLISH")==0)
{
title = "Error";
switch (error)
{
case IM_ERR_OPEN:
msg = "Error Opening File.";
break;
case IM_ERR_MEM:
msg = "Insuficient memory.";
break;
case IM_ERR_ACCESS:
msg = "Error Accessing File.";
break;
case IM_ERR_DATA:
msg = "Image type not Suported.";
break;
case IM_ERR_FORMAT:
msg = "Invalid Format.";
break;
case IM_ERR_COMPRESS:
msg = "Invalid or unsupported compression.";
break;
default:
msg = "Unknown Error.";
}
}
else
{
title = "Erro";
switch (error)
{
case IM_ERR_OPEN:
msg = "Erro Abrindo Arquivo.";
break;
case IM_ERR_MEM:
msg = "Memória Insuficiente.";
break;
case IM_ERR_ACCESS:
msg = "Erro Acessando Arquivo.";
break;
case IM_ERR_DATA:
msg = "Tipo de Imagem não Suportado.";
break;
case IM_ERR_FORMAT:
msg = "Formato Inválido.";
break;
case IM_ERR_COMPRESS:
msg = "Compressão Inválida ou não Suportada.";
break;
default:
msg = "Erro Desconhecido.";
}
}
if (interactive)
IupMessage(title, msg);
else
printf("%s: %s", title, msg);
}
</pre>
<h3><a name="formats">About File Formats</a></h3>
<p>TIFF is still the most complete format available. It could be better if
Adobe releases the revision 7, but it is on stand by. TIFF supports all the IM
image representation concepts. In fact we were partially inspired by the TIFF
specification. My suggestion is whenever possible use TIFF.</p>
<p>But TIFF may not be the ideal format for many situations. The W3C standards
include only JPEG, GIF and PNG for Web browsers. JPEG forces the image to be
RGB or Gray with a lossy compressed. GIF forces the image to be MAP with LZW
compression. PNG forces the image to be RGB, MAP, Gray or Binary, with Deflate
compression. So these characteristics are necessary to force small values for
faster downloads.</p>
<p>JPEG is to be used for photographic content, PNG should be used for the
remaining cases, but GIF is still the best to do simple animated images.</p>
<p>Except for some specific cases where a format is needed for compatibility,
the other formats are less important. TGA, PCX, RAS, SGI and BMP have almost
the same utility.</p>
<p>JP2 must be used for JPEG-2000 compression, would be nice if a new TIFF
specification includes this standard.</p>
<p>Since PNM has a textual header it is very simple to teach for students so
they can actually "see" the header. It is also a format easy to share images,
but it does not do much more than that.</p>
<p>The TIFF and the GIF format also have support for multiple images. This
does not necessarily defines an animation, pyramid nor a volume, but some
times they are used in these ways. </p>
<p>GIF became very popular to build animations for the Web, and since the LZW
patent expired Unisys realized that charging the usage isn't going to work and
so they did not renew it. LZW is fully supported at IM.</p>
<p>IM also supports video formats like AVI and WMV as external libraries. In
these cases the frames are also loaded as a sequence of individual images.
Sound is not supported.</p>
<p>TIFF, JPEG and PNG have an extensive list of attributes, most of them are
listed in the documentation, but some custom attributes may come up when
reading an image from file.</p>
<h3><a name="filesdk">New File Formats</a></h3>
<p>Again the easiest way is to look at the source code of an already
implemented format. The RAS, BMP, TGA and SGI formats are very simple to
follow.</p>
<p>Basically you have to implement a class that inherits from <b>imFormat</b>
and implement its virtual methods. You can use the <b>imBinFile</b> functions
for I/O or use an external SDK.</p>
<p>For more information see
<a href="doxygen/group__filesdk.html">File
Format SDK</a>.</p>
<h3><a name="binfilemem">Memory I/O and Others</a></h3>
<p>For the majority of the formats, with the exception of the ones that use
external SDKs, the I/O is done by the <b>imBinFile</b> module.</p>
<p>This module can be configured to access other types of media by
implementing a driver. There are some predefined drivers see
<a href="doxygen/group__binfile.html">Reference
/ Utilities / Binary File Access</a>.</p>
<p>One very useful is the <b>Memory Buffer</b> where you can read and write a
file in memory. The activation is very simple, it needs to happen just before
the <b>imFileOpen/imFileNew</b> functions. But the file name must be a
pointer to an <b>imBinMemoryFileName </b>structure instead of a string.
Se the example bellow:</p>
<pre>int old_mode = imBinFileSetCurrentModule(IM_MEMFILE);
imBinMemoryFileName MemFileName; // This structure must exists
while the file remains open.<br>
MemFileName.buffer = NULL; // Let the library initializes the buffer, <br>
// but it must be freed the the application, free(MemFileName.buffer)
MemFileName.size = 1024; // The initial size<br>
MemFileName.reallocate = 1.5; // The reallocation will increase 50% the
buffer.<br>
// This is used only when writing with a variable buffer.<br>
// Use 0 to fix the buffer size.
int error;<br>
imFile* ifile = imFileNew((const char*)&MemFileName, "GIF", &error);
imBinFileSetCurrentModule(old_mode); // The mode needs to be active
only for the imFileOpen/imFileNew call.
if (error != IM_ERR_NONE) ....</pre>
<p>Another driver interesting is the <b>Subfile</b> where you can read and
write from a file that is already open. This is very important for formats
that can have an embedded format inside. In this module the file_name
<span class="comment">is a pointer to an <b>imBinFile</b>
structure from any other module that uses the <b>imBinFile</b> functions. The
<b>imBinFileSize</b> will return the full file size, but the <b>imBinFileSeekTo</b> and
<b>imBinFileTell</b> functions will
compensate the position when the subfile was open.</span></p>
<p><span class="comment">Using </span><b>imBinFileSetCurrentModule(IM_SUBFILE)</b> just like the example above will
allow you to open a subfile using the <b>imFileOpen/imFileNew</b>
functions.</p>
</body>
</html>
|