Skip to content

Commit

Permalink
Make captions much more flexible, allowing a single shared caption
Browse files Browse the repository at this point in the history
file as well as individual imgname.jpg.cap files.
Don't confuse captions with image comment -- they're two different
things -- and allow setting them through the keywords dialog.
  • Loading branch information
akkana committed Apr 11, 2012
1 parent 6e5b82b commit eab6b28
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 80 deletions.
6 changes: 4 additions & 2 deletions gdialogs.c
Expand Up @@ -221,7 +221,10 @@ static gint HandleInfoKeyPress(GtkWidget* widget, GdkEventKey* event)
void ToggleInfo() void ToggleInfo()
{ {
GtkWidget *ok; GtkWidget *ok;
GtkWidget *label, *vbox, *box, *scroller; GtkWidget *label, *vbox, *box;
#ifdef SCROLLER
GtkWidget *scroller;
#endif
int i; int i;


if (gDebug) printf("ToggleInfo\n"); if (gDebug) printf("ToggleInfo\n");
Expand Down Expand Up @@ -259,7 +262,6 @@ void ToggleInfo()
vbox); vbox);
gtk_widget_show(vbox); gtk_widget_show(vbox);
#else /* SCROLLER */ #else /* SCROLLER */
scroller = 0; /* warning fix */
vbox = GTK_DIALOG(InfoDialog)->vbox; vbox = GTK_DIALOG(InfoDialog)->vbox;
#endif /* SCROLLER */ #endif /* SCROLLER */


Expand Down
23 changes: 8 additions & 15 deletions gmain.c
Expand Up @@ -18,7 +18,7 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>


char * gCapFileFormat = "%s.cap"; char * gCapFileFormat = "Captions";


/* Toggle a variable between two modes, preferring the first. /* Toggle a variable between two modes, preferring the first.
* If it's anything but mode1 it will end up as mode1. * If it's anything but mode1 it will end up as mode1.
Expand Down Expand Up @@ -300,23 +300,16 @@ static void CheckArg(char* arg)
else Usage(); else Usage();
if (gDebug) if (gDebug)
printf("Slideshow delay %d seconds\n", gDelaySeconds); printf("Slideshow delay %d seconds\n", gDelaySeconds);
} else if (*arg =='c') { } else if (*arg == 'c') {
int capfmtlen; gCapFileFormat = strdup(arg+1);
capfmtlen = strlen(arg+1);
if(capfmtlen == 0) {
fprintf(stderr, "Zero length argument to -c makes no sense\n");
Usage();
}
gCapFileFormat = calloc(1,capfmtlen+2);
strncpy(gCapFileFormat, arg+1, capfmtlen+1);
arg += capfmtlen;
if (gDebug) if (gDebug)
printf("Format set to '%s'\n", gCapFileFormat); printf("Format set to '%s'\n", gCapFileFormat);
if (strstr(gCapFileFormat, "%s") == NULL) {
fprintf(stderr, "Caption/comment file format string must contain a single %%s format marker,\nwhich is replaced by the file name\n"); /* Can't follow this with any other letters -- they're all
Usage(); * part of the filename -- so return.
*/
return;
} }
}
} }
} }


Expand Down
208 changes: 194 additions & 14 deletions imagenote.c
Expand Up @@ -93,13 +93,171 @@ void AddImgToList(char** strp, char* str)
free(str); free(str);
} }


/* Print a summary to a file, or stdout if NULL */
/* 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() void PrintNotes()
{ {
int i; int i;
char *rot90=0, *rot180=0, *rot270=0, *rot0=0, *unmatchExif=0; char *rot90=0, *rot180=0, *rot270=0, *rot0=0, *unmatchExif=0;
PhoImage* img; PhoImage *img;
int capfile; FILE *capfile = 0;
int useGlobalCaptionFile = GlobalCaptionFile();


/* Should free up memory here, e.g. for sFlagFileList, /* Should free up memory here, e.g. for sFlagFileList,
* but since this is only called right before exit, * but since this is only called right before exit,
Expand All @@ -111,16 +269,36 @@ void PrintNotes()
img = gFirstImage; img = gFirstImage;
while (img) while (img)
{ {
if (img->comment) { if (img->caption && img->caption[0] && gCapFileFormat) {
printf("Comment %s: %s\n", img->filename, img->comment); if (gDebug)
if (img->capname) { printf("Caption %s: %s\n", img->filename, img->caption);
capfile = open(img->capname, O_WRONLY|O_TRUNC|O_CREAT, 0666);
if (capfile >= 0) { /* If we have a global captions file and we haven't
write(capfile, img->comment,strlen(img->comment)); * opened it yet, do so now.
write(capfile, "\n",1); */
close(capfile); if (useGlobalCaptionFile && gCapFileFormat && !capfile) {
} else { capfile = fopen(gCapFileFormat, "w");
perror(img->capname); 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);
} }
} }
} }
Expand Down Expand Up @@ -166,6 +344,9 @@ void PrintNotes()
if (img == gFirstImage) break; if (img == gFirstImage) break;
} }


if (capfile)
fclose(capfile);

/* Now we've looped over all the structs, so we can print out /* Now we've looped over all the structs, so we can print out
* the tables of rotation and notes. * the tables of rotation and notes.
*/ */
Expand All @@ -191,4 +372,3 @@ void PrintNotes()
} }
printf("\n"); printf("\n");
} }

37 changes: 31 additions & 6 deletions keydialog.c
Expand Up @@ -11,8 +11,11 @@
#include <gdk/gdkkeysyms.h> #include <gdk/gdkkeysyms.h>
#include <stdio.h> /* needed on Mac, not on Linux, for sprintf */ #include <stdio.h> /* needed on Mac, not on Linux, for sprintf */
#include <ctype.h> #include <ctype.h>
#include <string.h>
#include <stdlib.h> /* for malloc() and free() */


static GtkWidget* KeywordsDialog = 0; static GtkWidget* KeywordsDialog = 0;
static GtkWidget* KeywordsCaption = 0;
static GtkWidget* KeywordsDEntry[NUM_NOTES] = {0}; static GtkWidget* KeywordsDEntry[NUM_NOTES] = {0};
static GtkWidget* KeywordsDToggle[NUM_NOTES] = {0}; static GtkWidget* KeywordsDToggle[NUM_NOTES] = {0};
static GtkWidget* KeywordsDImgName = 0; static GtkWidget* KeywordsDImgName = 0;
Expand All @@ -39,15 +42,23 @@ void RememberKeywords()
{ {
int i, mask, flags; int i, mask, flags;


if (!sLastImage)
return;

flags = 0; flags = 0;
for (i=0, mask=1; i < NUM_NOTES; ++i, mask <<= 1) for (i=0, mask=1; i < NUM_NOTES; ++i, mask <<= 1)
{ {
if (KeywordsDToggle[i] && if (KeywordsDToggle[i] &&
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(KeywordsDToggle[i]))) gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(KeywordsDToggle[i])))
flags |= mask; flags |= mask;
} }
if (sLastImage)
sLastImage->noteFlags = flags; sLastImage->noteFlags = flags;

/* and save a caption, if any */
if (sLastImage->caption)
free(sLastImage->caption);
sLastImage->caption = strdup((char*)gtk_entry_get_text((GtkEntry*)KeywordsCaption));
} }


void SetKeywordsDialogToggle(int which, int newval) void SetKeywordsDialogToggle(int which, int newval)
Expand All @@ -72,8 +83,8 @@ void UpdateKeywordsDialog()
sprintf(buffer, "pho keywords (%s)", gCurImage->filename); sprintf(buffer, "pho keywords (%s)", gCurImage->filename);
gtk_window_set_title(GTK_WINDOW(KeywordsDialog), buffer); gtk_window_set_title(GTK_WINDOW(KeywordsDialog), buffer);


s = gCurImage->comment; s = gCurImage->caption;
/*gtk_entry_set_text(GTK_ENTRY(KeywordsDEntry), s ? s : "");*/ gtk_entry_set_text(GTK_ENTRY(KeywordsCaption), s ? s : "");


gtk_label_set_text(GTK_LABEL(KeywordsDImgName), gCurImage->filename); gtk_label_set_text(GTK_LABEL(KeywordsDImgName), gCurImage->filename);


Expand Down Expand Up @@ -190,7 +201,7 @@ static void AddNewKeywordField()
static void MakeNewKeywordsDialog() static void MakeNewKeywordsDialog()
{ {
GtkWidget *ok, *label; GtkWidget *ok, *label;
GtkWidget *dlg_vbox, *sep, *btn_box; GtkWidget *dlg_vbox, *sep, *btn_box, *hbox;
int i; int i;


/* Use a toplevel window, so it won't pop up centered on the image win */ /* Use a toplevel window, so it won't pop up centered on the image win */
Expand Down Expand Up @@ -235,10 +246,24 @@ static void MakeNewKeywordsDialog()
TRUE, TRUE, 4); TRUE, TRUE, 4);
gtk_widget_show(KeywordsDImgName); gtk_widget_show(KeywordsDImgName);


label = gtk_label_new("To add a new keyword, enter it in the last box and hit Enter:"); label = gtk_label_new("To add a new keyword, hit Enter in the last box:");
gtk_box_pack_start(GTK_BOX(KeywordsContainer), label, TRUE, TRUE, 4); gtk_box_pack_start(GTK_BOX(KeywordsContainer), label, TRUE, TRUE, 4);
gtk_widget_show(label); gtk_widget_show(label);


/* Add the caption field */
hbox = gtk_hbox_new(FALSE, 3);
gtk_box_pack_start(GTK_BOX(KeywordsContainer), hbox,
TRUE, TRUE, 4);
label = gtk_label_new("Caption:");
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 4);
gtk_widget_show(label);

KeywordsCaption = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), KeywordsCaption, TRUE, TRUE, 4);
gtk_widget_show(KeywordsCaption);

gtk_widget_show(hbox);

/* Make sure all the entries are initialized */ /* Make sure all the entries are initialized */
for (i=0; i < NUM_NOTES; ++i) for (i=0; i < NUM_NOTES; ++i)
KeywordsDEntry[i] = 0; KeywordsDEntry[i] = 0;
Expand Down

0 comments on commit eab6b28

Please sign in to comment.