Browse Source

add -copyreduced

David Rose 20 years ago
parent
commit
4030ea3a8e

+ 201 - 125
pandaapp/src/indexify/indexImage.cxx

@@ -96,7 +96,6 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
 
   PNMImage index_image;
 
-  Filename reduced_dir(archive_dir, "reduced/" + _dir->get_basename());
   Filename thumbnail_dir(archive_dir, "thumbs");
   Filename output_filename(thumbnail_dir, _name);
   output_filename.set_extension("jpg");
@@ -160,130 +159,17 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
   for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
     const PhotoInfo &pinfo = (*pi);
     Photo *photo = _dir->get_photo(pinfo._photo_index);
-    Filename photo_filename(_dir->get_dir(), photo->get_basename());
-    Filename reduced_filename(reduced_dir, photo->get_basename());
-    photo_filename.standardize();
-    reduced_filename.standardize();
     PNMImage reduced_image;
-
-    if (!dummy_mode && photo_filename != reduced_filename &&
-        (force_regenerate || 
-         reduced_filename.compare_timestamps(photo_filename) < 0)) {
-      // If the reduced filename does not exist or is older than the
-      // source filename, we must read the complete source filename to
-      // generate the reduced image.
-      PNMImage photo_image;
-      PNMReader *reader = photo_image.make_reader(photo_filename);
-      if (reader == (PNMReader *)NULL) {        
-        nout << "Unable to read " << photo_filename << ".\n";
-        return false;
-      }
-      photo_image.copy_header_from(*reader);
-      
-      photo->_full_x_size = photo_image.get_x_size();
-      photo->_full_y_size = photo_image.get_y_size();
-      
-      // Generate a reduced image for the photo.
-      compute_reduction(photo_image, reduced_image, 
-                        reduced_width, reduced_height);
-
-      photo->_reduced_x_size = reduced_image.get_x_size();
-      photo->_reduced_y_size = reduced_image.get_y_size();
-
-      // Only bother making a reduced version if it would actually be
-      // smaller than the original.
-      if (photo->_reduced_x_size < photo->_full_x_size ||
-          photo->_reduced_y_size < photo->_full_y_size) {
-	nout << "Reading " << photo_filename << "\n";
-        if (!photo_image.read(reader)) {
-          nout << "Unable to read.\n";
-          return false;
-        }
-	reader = NULL;
-
-        reduced_image.quick_filter_from(photo_image);
-        reduced_filename.make_dir();
-        nout << "Writing " << reduced_filename << "\n";
-        if (!reduced_image.write(reduced_filename)) {
-          nout << "Unable to write.\n";
-          delete reader;
-          return false;
-        }
-	photo->_has_reduced = true;
-
-      } else {
-	// We're not making a reduced version.  But maybe we still
-	// need to read the original so we can make a thumbnail.
-	reduced_filename = photo_filename;
-	reduced_image.copy_header_from(photo_image);
-
-	if (!dummy_mode && generate_index_image) {
-	  nout << "Reading " << photo_filename << "\n";
-	  if (!reduced_image.read(reader)) {
-	    nout << "Unable to read image.\n";
-	    return false;
-	  }
-	  reader = NULL;
-	}  
-      }
-      if (reader != (PNMReader *)NULL) {
-	delete reader;
-      }
-
-    } else {
-      // If the reduced image already exists and is newer than the
-      // source image, use it.
-
-      // We still read the image header to determine its size.
-      PNMImageHeader photo_image;
-      if (!photo_image.read_header(photo_filename)) {
-        nout << "Unable to read " << photo_filename << "\n";
-        return false;
-      }
-      
-      photo->_full_x_size = photo_image.get_x_size();
-      photo->_full_y_size = photo_image.get_y_size();
-      photo->_has_reduced = true;
-
-      if (dummy_mode) {
-        // In dummy mode, we may or may not actually have a reduced
-        // image.  In either case, ignore the file and compute its
-        // appropriate size from the source image.
-        compute_reduction(photo_image, reduced_image, reduced_width, reduced_height);
-        photo->_reduced_x_size = reduced_image.get_x_size();
-        photo->_reduced_y_size = reduced_image.get_y_size();
-
-      } else if (generate_index_image) {
-        // Now read the reduced image from disk, so we can put it on
-        // the index image.
-        nout << "Reading " << reduced_filename << "\n";
-        
-        if (!reduced_image.read(reduced_filename)) {
-          nout << "Unable to read.\n";
-          return false;
-        }
-
-        photo->_reduced_x_size = reduced_image.get_x_size();
-        photo->_reduced_y_size = reduced_image.get_y_size();
-
-      } else {
-        // If we're not generating an index image, we don't even need
-        // the reduced image--just scan its header to get its size.
-        if (!reduced_image.read_header(reduced_filename)) {
-          nout << "Unable to read " << reduced_filename << "\n";
-          return false;
-        }
-        photo->_reduced_x_size = reduced_image.get_x_size();
-        photo->_reduced_y_size = reduced_image.get_y_size();
-      }
+    if (!make_reduced_image(photo, reduced_image, generate_index_image, false)) {
+      return false;
     }
-
+  
     if (generate_index_image) {
       // Generate a thumbnail image for the photo.
       PNMImage thumbnail_image;
       compute_reduction(reduced_image, thumbnail_image, 
                         thumb_interior_width, thumb_interior_height);
-
+      
       if (dummy_mode) {
         draw_box(thumbnail_image);
       } else {
@@ -292,7 +178,7 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
       // Center the thumbnail image within its box.
       int x_center = (thumb_width - thumbnail_image.get_x_size()) / 2;
       int y_center = (thumb_height - thumbnail_image.get_y_size()) / 2;
-
+      
       if (draw_frames) {
         draw_frame(index_image, 
                    pinfo._x_place, pinfo._y_place,
@@ -300,16 +186,16 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
                    pinfo._x_place + x_center, pinfo._y_place + y_center,
                    thumbnail_image.get_x_size(), thumbnail_image.get_y_size());
       }
-
+      
       thumbnail_image.set_color_type(index_image.get_color_type());
       index_image.copy_sub_image(thumbnail_image, 
                                  pinfo._x_place + x_center, 
                                  pinfo._y_place + y_center);
-
+      
       if (text_maker != (PNMTextMaker *)NULL) {
         int label_x = pinfo._x_place + thumb_width / 2;
         int label_y = pinfo._y_place + thumb_height + thumb_caption_height;
-
+        
         int width = 
           text_maker->generate_into(photo->get_frame_number(), index_image, 
                                     label_x, label_y);
@@ -340,6 +226,159 @@ generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: IndexImage::make_reduced_image
+//       Access: Public
+//  Description: Copies the full-sized image to the reduced image
+//               folder, if necessary.
+////////////////////////////////////////////////////////////////////
+bool IndexImage::
+make_reduced_image(Photo *photo, PNMImage &reduced_image, 
+                   bool generate_index_image, bool force_reduced) {
+  Filename reduced_dir(archive_dir, "reduced/" + _dir->get_basename());
+
+  Filename photo_filename(_dir->get_dir(), photo->get_basename());
+  Filename reduced_filename(reduced_dir, photo->get_basename());
+  photo_filename.standardize();
+  reduced_filename.standardize();
+  
+  if (!dummy_mode && photo_filename != reduced_filename &&
+      (force_regenerate || 
+       reduced_filename.compare_timestamps(photo_filename) < 0)) {
+    // If the reduced filename does not exist or is older than the
+    // source filename, we must read the complete source filename to
+    // generate the reduced image.
+    PNMImage photo_image;
+    PNMReader *reader = photo_image.make_reader(photo_filename);
+    if (reader == (PNMReader *)NULL) {        
+      nout << "Unable to read " << photo_filename << ".\n";
+      return false;
+    }
+    photo_image.copy_header_from(*reader);
+    
+    photo->_full_x_size = photo_image.get_x_size();
+    photo->_full_y_size = photo_image.get_y_size();
+    
+    // Generate a reduced image for the photo.
+    compute_reduction(photo_image, reduced_image, 
+                      reduced_width, reduced_height);
+    
+    photo->_reduced_x_size = reduced_image.get_x_size();
+    photo->_reduced_y_size = reduced_image.get_y_size();
+    
+    // Only bother making a reduced version if it would actually be
+    // smaller than the original.
+    if (photo->_reduced_x_size < photo->_full_x_size ||
+        photo->_reduced_y_size < photo->_full_y_size) {
+      nout << "Reading " << photo_filename << "\n";
+      if (!photo_image.read(reader)) {
+        nout << "Unable to read.\n";
+        return false;
+      }
+      reader = NULL;
+      
+      reduced_image.quick_filter_from(photo_image);
+      reduced_filename.make_dir();
+      nout << "Writing " << reduced_filename << "\n";
+      if (!reduced_image.write(reduced_filename)) {
+        nout << "Unable to write.\n";
+        delete reader;
+        return false;
+      }
+      photo->_has_reduced = true;
+
+    } else if (force_reduced) {
+      // Even though the reduced image would not be smaller, copy it
+      // anyway when force_reduced is true.
+      nout << "Reading " << photo_filename << "\n";
+      if (!reduced_image.read(reader)) {
+        nout << "Unable to read.\n";
+        return false;
+      }
+      reader = NULL;
+      
+      reduced_filename.make_dir();
+      nout << "Writing " << reduced_filename << "\n";
+      if (!reduced_image.write(reduced_filename)) {
+        nout << "Unable to write.\n";
+        delete reader;
+        return false;
+      }
+      photo->_has_reduced = true;
+
+      photo->_reduced_x_size = reduced_image.get_x_size();
+      photo->_reduced_y_size = reduced_image.get_y_size();
+      
+    } else {
+      // We're not making a reduced version.  But maybe we still
+      // need to read the original so we can make a thumbnail.
+      reduced_filename = photo_filename;
+      reduced_image.copy_header_from(photo_image);
+      
+      if (!dummy_mode && generate_index_image) {
+        nout << "Reading " << photo_filename << "\n";
+        if (!reduced_image.read(reader)) {
+          nout << "Unable to read image.\n";
+          return false;
+        }
+        reader = NULL;
+      }  
+    }
+    if (reader != (PNMReader *)NULL) {
+      delete reader;
+    }
+    
+  } else {
+    // If the reduced image already exists and is newer than the
+    // source image, use it.
+    
+    // We still read the image header to determine its size.
+    PNMImageHeader photo_image;
+    if (!photo_image.read_header(photo_filename)) {
+      nout << "Unable to read " << photo_filename << "\n";
+      return false;
+    }
+    
+    photo->_full_x_size = photo_image.get_x_size();
+    photo->_full_y_size = photo_image.get_y_size();
+    photo->_has_reduced = true;
+    
+    if (dummy_mode) {
+      // In dummy mode, we may or may not actually have a reduced
+      // image.  In either case, ignore the file and compute its
+      // appropriate size from the source image.
+      compute_reduction(photo_image, reduced_image, reduced_width, reduced_height);
+      photo->_reduced_x_size = reduced_image.get_x_size();
+      photo->_reduced_y_size = reduced_image.get_y_size();
+      
+    } else if (generate_index_image) {
+      // Now read the reduced image from disk, so we can put it on
+      // the index image.
+      nout << "Reading " << reduced_filename << "\n";
+      
+      if (!reduced_image.read(reduced_filename)) {
+        nout << "Unable to read.\n";
+        return false;
+      }
+      
+      photo->_reduced_x_size = reduced_image.get_x_size();
+      photo->_reduced_y_size = reduced_image.get_y_size();
+      
+    } else {
+      // If we're not generating an index image, we don't even need
+      // the reduced image--just scan its header to get its size.
+      if (!reduced_image.read_header(reduced_filename)) {
+        nout << "Unable to read " << reduced_filename << "\n";
+        return false;
+      }
+      photo->_reduced_x_size = reduced_image.get_x_size();
+      photo->_reduced_y_size = reduced_image.get_y_size();
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: IndexImage::generate_html
 //       Access: Public
@@ -397,6 +436,44 @@ generate_html(ostream &root_html, const Filename &archive_dir,
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: IndexImage::copy_reduced
+//       Access: Public
+//  Description: Copies key files from the full directory into the
+//               reduced directory.
+////////////////////////////////////////////////////////////////////
+bool IndexImage::
+copy_reduced(const Filename &archive_dir) {
+  Photos::const_iterator pi;
+  for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
+    const PhotoInfo &pinfo = (*pi);
+    int photo_index = pinfo._photo_index;
+    Photo *photo = _dir->get_photo(pinfo._photo_index);
+
+    // Make sure we have a "reduced" image.
+    PNMImage reduced_image;
+    if (!make_reduced_image(photo, reduced_image, false, true)) {
+      return false;
+    }
+
+    if (photo->_has_movie) {
+      // Also copy the movie file to the reduced directory, even
+      // though it's not reduced in any way--but there's no way
+      // (presently) to reduce a movie file.
+      Filename movie_filename(_dir->get_dir(), photo->get_movie());
+      if (movie_filename.exists()) {
+        movie_filename.set_binary();
+        Filename reduced_dir(archive_dir, "reduced/" + _dir->get_basename());
+        if (!copy_file(movie_filename, reduced_dir)) {
+          return false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: IndexImage::output
 //       Access: Public
@@ -528,11 +605,10 @@ generate_reduced_html(ostream &html, Photo *photo, int photo_index, int pi,
   generate_nav_buttons(html, prev_photo_filename, next_photo_filename,
                        up_href);
 
-  Filename cm_filename(_dir->get_dir(), photo->get_basename());
-  cm_filename.set_extension("cm");
-  if (cm_filename.exists()) {
+  if (photo->_has_cm) {
     // If a comment file for the photo exists, insert its contents
     // here, right above the photo.
+    Filename cm_filename(_dir->get_dir(), photo->get_cm());
     if (!RollDirectory::insert_html_comment(html, cm_filename)) {
       return false;
     }

+ 5 - 0
pandaapp/src/indexify/indexImage.h

@@ -43,9 +43,14 @@ public:
 
   bool add_photo(int index);
   bool generate_images(const Filename &archive_dir, PNMTextMaker *text_maker);
+  bool make_reduced_image(Photo *photo, PNMImage &reduced_image, 
+                          bool generate_index_image, bool force_reduced);
+
   bool generate_html(ostream &root_html, const Filename &archive_dir,
                      const Filename &roll_dir_root);
 
+  bool copy_reduced(const Filename &archive_dir);
+
   void output(ostream &out) const;
   void write(ostream &out, int indent_level) const;
 

+ 41 - 0
pandaapp/src/indexify/indexParameters.cxx

@@ -228,3 +228,44 @@ escape_html(const string &input) {
 
   return result;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: copy_file
+//  Description: Copies a file into the named directory, if it does
+//               not already exist there.  Returns true if
+//               successful, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool
+copy_file(const Filename &source_file, const Filename &dest_dir) {
+  Filename dest_file = source_file;
+  dest_file.set_dirname(dest_dir);
+
+  if (dest_file.exists()) {
+    return true;
+  }
+
+  if (!source_file.exists()) {
+    return false;
+  }
+
+  ifstream in;
+  if (!source_file.open_read(in)) {
+    cerr << "Unable to read " << source_file << "\n";
+    return false;
+  }
+  ofstream out;
+  if (!dest_file.open_write(out)) {
+    cerr << "Unable to write " << dest_file << "\n";
+    return false;
+  }
+
+  cerr << "Copying " << source_file << " to " << dest_file << "\n";
+
+  int c = in.get();
+  while (in && !in.eof()) {
+    out.put(c);
+    c = in.get();
+  }
+
+  return in.eof();
+}

+ 1 - 0
pandaapp/src/indexify/indexParameters.h

@@ -145,6 +145,7 @@ Filename compose_href(const Filename &rel_dir, const Filename &user_prefix,
 		      const Filename &basename = Filename());
 
 string escape_html(const string &input);
+bool copy_file(const Filename &source_file, const Filename &dest_dir);
 
 #endif
 

+ 43 - 0
pandaapp/src/indexify/indexify.cxx

@@ -252,6 +252,14 @@ Indexify() {
      "there are one or more movie files found in the directory.",
      &Indexify::dispatch_filename, NULL, &movie_icon);
 
+  add_option
+    ("copyreduced", "", 0,
+     "Instead of generating index files, copy key files (such as "
+     "*.cm, *.ds) from the full image directory into the reduced "
+     "image directory, so that the full image directory may be removed "
+     "for generating a reduced-size archive.",
+     &Indexify::dispatch_none, &_copy_reduced);
+
   _photo_extension = "jpg";
   _movie_extension = "mov";
   _text_maker = (PNMTextMaker *)NULL;
@@ -549,7 +557,23 @@ run() {
     exit(1);
   }
 
+  if (_copy_reduced) {
+    do_copy_reduced();
+  } else {
+    do_generate_images();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Indexify::do_generate_images
+//       Access: Public
+//  Description: The main work function.  Generates all of the reduced
+//               images and the html code.
+////////////////////////////////////////////////////////////////////
+void Indexify::
+do_generate_images() {
   // First, generate all the images.
+  RollDirs::iterator di;
   for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
     RollDirectory *roll_dir = (*di);
     if (!roll_dir->generate_images(archive_dir, _text_maker)) {
@@ -657,6 +681,25 @@ run() {
     << "</html>\n";
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Indexify::do_copy_reduced
+//       Access: Public
+//  Description: The main work function in -copyreduced mode.  Simply
+//               copies key files from the full directory to the
+//               reduced directory.
+////////////////////////////////////////////////////////////////////
+void Indexify::
+do_copy_reduced() {
+  RollDirs::iterator di;
+  for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
+    RollDirectory *roll_dir = (*di);
+    if (!roll_dir->copy_reduced(archive_dir)) {
+      nout << "Failure.\n";
+      exit(1);
+    }
+  }
+}
+
 
 int main(int argc, char *argv[]) {
   Indexify prog;

+ 3 - 0
pandaapp/src/indexify/indexify.h

@@ -48,6 +48,8 @@ protected:
 
 public:
   void run();
+  void do_generate_images();
+  void do_copy_reduced();
 
   string _front_title;
   Filename _roll_dir_root;
@@ -56,6 +58,7 @@ public:
   Filename _font_filename;
   bool _generate_icons;
   double _font_aa_factor;
+  bool _copy_reduced;
 
   typedef pvector<RollDirectory *> RollDirs;
   RollDirs _roll_dirs;

+ 29 - 4
pandaapp/src/indexify/photo.cxx

@@ -27,10 +27,9 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 Photo::
-Photo(RollDirectory *dir, const Filename &basename, const Filename &movie) :
+Photo(RollDirectory *dir, const Filename &basename, const string &movie_extension) :
   _dir(dir),
-  _basename(basename),
-  _movie(movie)
+  _basename(basename)
 {
   _name = _basename.get_basename_wo_extension();
   _frame_number = _name;
@@ -52,7 +51,22 @@ Photo(RollDirectory *dir, const Filename &basename, const Filename &movie) :
   _reduced_x_size = 0;
   _reduced_y_size = 0;
   _has_reduced = false;
-  _has_movie = !_movie.empty();
+
+  _has_movie = false;
+  Filename movie_filename(_dir->get_dir(), _basename);
+  movie_filename.set_extension(movie_extension);
+  if (movie_filename.exists()) {
+    _movie = movie_filename.get_basename();
+    _has_movie = true;
+  }
+
+  _has_cm = false;
+  Filename cm_filename(_dir->get_dir(), _basename);
+  cm_filename.set_extension("cm");
+  if (cm_filename.exists()) {
+    _cm = cm_filename.get_basename();
+    _has_cm = true;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -77,6 +91,17 @@ get_movie() const {
   return _movie;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Photo::get_cm
+//       Access: Public
+//  Description: Returns the filename of the comment file associated
+//               with the photo, if any.
+////////////////////////////////////////////////////////////////////
+const Filename &Photo::
+get_cm() const {
+  return _cm;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Photo::get_name
 //       Access: Public

+ 4 - 1
pandaapp/src/indexify/photo.h

@@ -32,10 +32,11 @@ class RollDirectory;
 class Photo {
 public:
   Photo(RollDirectory *dir, const Filename &basename, 
-        const Filename &movie = Filename());
+        const string &movie_extension);
 
   const Filename &get_basename() const;
   const Filename &get_movie() const;
+  const Filename &get_cm() const;
   const string &get_name() const;
   const string &get_frame_number() const;
 
@@ -48,11 +49,13 @@ public:
   int _reduced_y_size;
   bool _has_reduced;
   bool _has_movie;
+  bool _has_cm;
 
 private:
   RollDirectory *_dir;
   Filename _basename;
   Filename _movie;
+  Filename _cm;
   string _name;
   string _frame_number;
 };

+ 68 - 26
pandaapp/src/indexify/rollDirectory.cxx

@@ -36,14 +36,18 @@ RollDirectory::
 RollDirectory(const Filename &dir) :
   _dir(dir)
 {
+  _prev = (RollDirectory *)NULL;
+  _next = (RollDirectory *)NULL;
+
   _basename = _dir.get_basename();
   if (format_rose) {
     _name = format_basename(_basename);
   } else {
     _name = _basename;
   }
-  _prev = (RollDirectory *)NULL;
-  _next = (RollDirectory *)NULL;
+
+  _got_ds_file = false;
+  _got_ls_file = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -123,19 +127,20 @@ scan(const string &photo_extension, const string &movie_extension) {
 
   // Check for a .ds file, which contains a one-line description of
   // the contents of the directory.
-  Filename ds_filename(_basename);
-  ds_filename.set_extension("ds");
-  if (cm_search.is_empty() || !ds_filename.resolve_filename(cm_search)) {
+  _ds_filename = Filename(_basename);
+  _ds_filename.set_extension("ds");
+  if (cm_search.is_empty() || !_ds_filename.resolve_filename(cm_search)) {
     // If the ds file isn't found along the search path specified
     // via -cmdir on the command line, then look for it in the
     // appropriate source directory.
-    ds_filename = Filename(_dir, ds_filename);
+    _ds_filename = Filename(_dir, _ds_filename);
   }
-  if (ds_filename.exists()) {
-    ds_filename.set_text();
+  if (_ds_filename.exists()) {
+    _got_ds_file = true;
+    _ds_filename.set_text();
     ifstream ds;
-    if (!ds_filename.open_read(ds)) {
-      nout << "Could not read " << ds_filename << "\n";
+    if (!_ds_filename.open_read(ds)) {
+      nout << "Could not read " << _ds_filename << "\n";
     } else {
       // Get the words out one at a time and put just one space
       // between them.
@@ -160,14 +165,15 @@ scan(const string &photo_extension, const string &movie_extension) {
 
   // Check for an .ls file in the roll directory, which may give an
   // explicit ordering, or if empty, it specifies reverse ordering.
-  Filename ls_filename(_dir, _basename);
-  ls_filename.set_extension("ls");
-  if (ls_filename.exists()) {
-    add_contributing_filename(ls_filename);
-    ls_filename.set_text();
+  _ls_filename = Filename(_dir, _basename);
+  _ls_filename.set_extension("ls");
+  if (_ls_filename.exists()) {
+    _got_ls_file = true;
+    add_contributing_filename(_ls_filename);
+    _ls_filename.set_text();
     ifstream ls;
-    if (!ls_filename.open_read(ls)) {
-      nout << "Could not read " << ls_filename << "\n";
+    if (!_ls_filename.open_read(ls)) {
+      nout << "Could not read " << _ls_filename << "\n";
     } else {
       bool any_words = false;
       string word;
@@ -511,8 +517,13 @@ generate_html(const Filename &archive_dir, const Filename &roll_dir_root) {
   generate_nav_buttons(index_html, prev_roll_filename, next_roll_filename,
                        up_href);
 
+  if (!omit_complete) {
+    index_html
+      << "<a href=\"complete.htm#" << _basename
+      << "\">(complete archive)</a>\n";
+  }
+
   index_html
-    << "<a href=\"complete.htm#" << _basename << "\">(complete archive)</a>\n"
     << "</body>\n"
     << "</html>\n";
 
@@ -552,6 +563,44 @@ get_index_html() const {
   return _index_html;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RollDirectory::copy_reduced
+//       Access: Public
+//  Description: Copies key files from the full directory into the
+//               reduced directory.
+////////////////////////////////////////////////////////////////////
+bool RollDirectory::
+copy_reduced(const Filename &archive_dir) {
+  if (is_empty()) {
+    return true;
+  }
+  nassertr(!_index_images.empty(), false);
+
+  Filename reduced_dir(archive_dir, "reduced/" + _dir.get_basename());
+
+  if (_got_ds_file) {
+    if (!copy_file(_ds_filename, reduced_dir)) {
+      return false;
+    }
+  }
+
+  if (_got_ls_file) {
+    if (!copy_file(_ls_filename, reduced_dir)) {
+      return false;
+    }
+  }
+
+  IndexImages::iterator ii;
+  for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
+    IndexImage *index_image = (*ii);
+    if (!index_image->copy_reduced(archive_dir)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RollDirectory::output
 //       Access: Public
@@ -639,14 +688,7 @@ insert_html_comment(ostream &html, Filename cm_filename) {
 ////////////////////////////////////////////////////////////////////
 void RollDirectory::
 add_photo(const Filename &basename, const string &movie_extension) {
-  Photo *photo = NULL;
-  Filename movie_filename(_dir, basename);
-  movie_filename.set_extension(movie_extension);
-  if (movie_filename.exists()) {
-    photo = new Photo(this, basename, movie_filename.get_basename());
-  } else {
-    photo = new Photo(this, basename);
-  }
+  Photo *photo = new Photo(this, basename, movie_extension);
   _photos.push_back(photo);
 }
 

+ 7 - 0
pandaapp/src/indexify/rollDirectory.h

@@ -62,6 +62,8 @@ public:
   const string &get_comment_html() const;
   const string &get_index_html() const;
 
+  bool copy_reduced(const Filename &archive_dir);
+
   void output(ostream &out) const;
   void write(ostream &out, int indent_level) const;
 
@@ -89,6 +91,11 @@ private:
   string _desc;
   typedef pvector<Photo *> Photos;
   Photos _photos;
+
+  bool _got_ds_file;
+  Filename _ds_filename;
+  bool _got_ls_file;
+  Filename _ls_filename;
   
   Filename _newest_contributing_filename;