-
Notifications
You must be signed in to change notification settings - Fork 7
/
imagenote.c
374 lines (325 loc) · 10.8 KB
/
imagenote.c
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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
/*
* imagenote.c: save info about images. For pho, an image viewer.
*
* Copyright 2002,2007 by Akkana Peck.
* You are free to use or modify this code under the Gnu Public License.
*/
#include "pho.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h> /* for malloc() */
#include <glib.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h> /* for write() */
static char *sFlagFileList[NUM_NOTES];
void InitNotes()
{
int i;
for (i=0; i<NUM_NOTES; ++i)
sFlagFileList[i] = 0;
}
void ToggleNoteFlag(PhoImage* img, int note)
{
int bit = (1 << note);
if (img->noteFlags & bit)
img->noteFlags &= ~bit;
else
img->noteFlags |= bit;
/* Update any dialogs which might be showing toggles */
SetInfoDialogToggle(note, (img->noteFlags & bit) != 0);
SetKeywordsDialogToggle(note, (img->noteFlags & bit) != 0);
}
/* Guard against filenames which contain odd characters, like
* spaces or quotes. Returns allocated memory.
*/
char *QuoteString(char *str)
{
int i;
char *newstr;
/* look for a space or quote in str */
for (i = 0; str[i] != '\0'; i++)
if (isspace(str[i]) || (str[i] == '\"') || (str[i] == '\'')) {
GString *gstr = g_string_new("\"");
for (i = 0; str[i] != '\0'; i++) {
if (str[i] == '\"')
g_string_append(gstr, (gchar *)"\\\"");
/*else if (str[i] == '\'')
g_string_append(gstr, (gchar *)"\\\'");*/
else
g_string_append_c(gstr, (gchar)str[i]);
}
g_string_append_c(gstr, '\"');
newstr = gstr->str;
g_string_free(gstr, FALSE);
return newstr;
}
/* If there are no spaces or quotes in str, return a copy of str */
return (char *)g_strdup((gchar *)str);
}
void AddImgToList(char** strp, char* str)
{
str = QuoteString(str);
if (*strp)
{
int newsize = strlen(*strp) + strlen(str) + 2;
char* newstr = malloc(newsize);
if (!newstr) {
free(str);
*strp = 0;
return;
}
snprintf(newstr, newsize, "%s %s", *strp, str);
free(*strp);
*strp = newstr;
}
else
*strp = strdup(str);
/* QuoteString allocated a copy, so free that now: */
free(str);
}
/* Captions:
* captions may be stored in one file per image, or they may
* all be in one file in lines like
* imgname: caption
* This is controlled by gCapFileFormat: if it has a %s in it,
* that will be replaced by the current image file name.
*/
static int GlobalCaptionFile()
{
char* cp;
/* For captions, are we going to put them all in one file,
* or in individual files? That's controlled by whether
* gCapFileFormat includes a '%s" in it, i.e., will it
* substitute the name of the image file inside caption filenames.
*/
for (cp = gCapFileFormat; *cp != 0; ++cp) {
if (cp[0] == '%' && cp[1] == 's')
return 0;
}
/* If we got throught he loop without seeing %s, then the
* caption file is global.
*/
return 1;
}
/* Return the appropriate caption file name for this image */
static char* CapFileName(PhoImage* img)
{
/* How much ram do we need for the caption filename? */
static char buf[BUFSIZ];
int caplength = snprintf(buf, BUFSIZ, gCapFileFormat, img->filename);
if (strncmp(img->filename, buf, caplength) == 0) {
fprintf(stderr,
"Caption filename expanded to same as image filename. Bailing!\n");
return 0;
}
return buf;
}
/* Read any caption that might be in the caption file.
* If the caption file is global, though, we read the file once
* for the first image and cache them.
*/
void ReadCaption(PhoImage* img)
{
int i;
int capfile;
char* capfilename;
static int sFirstTime = 1;
static int sGlobalCaptions = 0;
static char** sCaptionFileList = 0;
static char** sCaptionList = 0;
static int sNumCaptions = 0;
if (sFirstTime) {
sFirstTime = 0;
sGlobalCaptions = GlobalCaptionFile();
if (sGlobalCaptions) {
/* Read the global file */
char line[10000];
int numlines = 0;
FILE* capfile = fopen(gCapFileFormat, "r");
if (!capfile) /* No captions to read, nothing to do */
return;
/* Make a first pass through the file just to count lines */
while (fgets(line, sizeof line, capfile)) {
char* colon = strchr(line, ':');
if (colon)
++numlines;
}
/* Now we can allocate space for the lists of files/captions */
sCaptionFileList = malloc(numlines * (sizeof (char*)));
sCaptionList = malloc(numlines * (sizeof (char*)));
/* and loop through again to actually read the captions */
rewind(capfile);
while (fgets(line, sizeof line, capfile)) {
char* cp;
/* Line should look like: imagename: blah blah */
char* colon = strchr(line, ':');
if (!colon) continue;
/* terminate the filename string */
*colon = '\0';
sCaptionFileList[sNumCaptions] = strdup(line);
/* Skip the colon and any spaces immediately after it */
++colon;
while (*colon == ' ')
++colon;
/* strip off the terminal newline */
for (cp = colon; *cp != '\0'; ++cp)
if (*cp == '\n' || *cp == '\r') {
*cp = '\0';
break;
}
/* Now colon points to the beginning of the caption */
sCaptionList[sNumCaptions] = strdup(colon);
++sNumCaptions;
}
fclose(capfile);
}
}
/* Now we've done the first-time reading of the file, if needed. */
if (sGlobalCaptions) {
for (i=0; i < sNumCaptions; ++i)
if (!strcmp(sCaptionFileList[i], img->filename)) {
img->caption = sCaptionList[i];
return;
}
img->caption = 0;
return;
}
/* If we get here, caption files are per-image.
* So look for the appropriate caption file.
*/
capfilename = CapFileName(img);
if (!capfilename)
return;
capfile = open(capfilename, O_RDONLY);
if (capfile < 0)
return;
printf("Reading caption from %s\n", capfilename);
#define MAX_CAPTION 1023
img->caption = calloc(1, MAX_CAPTION);
if (!(img->caption)) {
perror("Couldn't allocate memory for caption");
return;
}
read(capfile, img->caption, MAX_CAPTION-1);
for (i=0; i < MAX_CAPTION && img->caption[i] != 0; ++i) {
if (img->caption[i] == '\n') {
img->caption[i] = ' ';
}
}
close(capfile);
if (gDebug)
fprintf(stderr, "Read caption file %s\n", capfilename);
}
/* Finally, the routine that prints a summary to a file or stdout */
void PrintNotes()
{
int i;
char *rot90=0, *rot180=0, *rot270=0, *rot0=0, *unmatchExif=0;
PhoImage *img;
FILE *capfile = 0;
int useGlobalCaptionFile = GlobalCaptionFile();
/* Should free up memory here, e.g. for sFlagFileList,
* but since this is only called right before exit,
* it's never been allocated so it doesn't matter.
* If PrintNotes ever gets called except at exit,
* this will leak.
*/
img = gFirstImage;
while (img)
{
if (img->caption && img->caption[0] && gCapFileFormat) {
if (gDebug)
printf("Caption %s: %s\n", img->filename, img->caption);
/* If we have a global captions file and we haven't
* opened it yet, do so now.
*/
if (useGlobalCaptionFile && gCapFileFormat && !capfile) {
capfile = fopen(gCapFileFormat, "w");
if (!capfile) {
perror(gCapFileFormat);
gCapFileFormat = 0; /* don't try again to write to it */
}
}
if (capfile) { /* One shared caption file */
/* capfile is already open, so append to it: */
fprintf(capfile, "%s: %s\n\n", img->filename, img->caption);
} else if (gCapFileFormat) { /* need individual caption files */
char* capname = CapFileName(img);
if (capname) {
capfile = fopen(capname, "w");
if (capfile) {
fputs(img->caption, capfile);
fclose(capfile);
capfile = 0;
}
else
perror(capname);
}
}
}
if (img->noteFlags)
{
int flag, j;
for (j=0, flag=1; j<NUM_NOTES; ++j, flag <<= 1)
if (img->noteFlags & flag)
AddImgToList(sFlagFileList+j, img->filename);
}
switch (img->curRot)
{
case 90:
AddImgToList(&rot90, img->filename);
break;
case 180:
AddImgToList(&rot180, img->filename);
break;
case 270:
case -90:
AddImgToList(&rot270, img->filename);
break;
case 0:
/* If the image is rotated at zero but the EXIF says otherwise,
* we need to list that too:
*/
if (img->exifRot != 0)
AddImgToList(&rot0, img->filename);
break;
default:
break;
}
/* If the user-chosen rotation doesn't match the EXIF,
* we need to know that too.
*/
if (img->curRot != img->exifRot)
AddImgToList(&unmatchExif, img->filename);
img = img->next;
/* Have we looped back to the beginning?*/
if (img == gFirstImage) break;
}
if (capfile)
fclose(capfile);
/* Now we've looped over all the structs, so we can print out
* the tables of rotation and notes.
*/
if (rot90)
printf("\nRotate 90 (CW): %s\n", rot90);
if (rot270)
printf("\nRotate -90 (CCW): %s\n", rot270);
if (rot180)
printf("\nRotate 180: %s\n", rot180);
if (rot0)
printf("\nRotate 0 (wrong EXIF): %s\n", rot0);
if (unmatchExif)
printf("\nWrong EXIF: %s\n", unmatchExif);
for (i=0; i < NUM_NOTES; ++i)
if (sFlagFileList[i])
{
char* keyword = KeywordString(i);
if (keyword && *keyword)
printf("\n%s: ", keyword);
else
printf("\nNote %d: ", i);
printf("%s\n", sFlagFileList[i]);
}
printf("\n");
}