Remove pandaapp completely
This commit is contained in:
parent
1735ae4600
commit
574199c94d
|
|
@ -1,59 +0,0 @@
|
|||
//
|
||||
// Package.pp
|
||||
//
|
||||
// This file defines certain configuration variables that are to be
|
||||
// written into the various make scripts. It is processed by ppremake
|
||||
// (along with the Sources.pp files in each of the various
|
||||
// directories) to generate build scripts appropriate to each
|
||||
// environment.
|
||||
//
|
||||
// This is the package-specific file, which should be at the top of
|
||||
// every source hierarchy. It generally gets the ball rolling, and is
|
||||
// responsible for explicitly including all of the relevent Config.pp
|
||||
// files.
|
||||
|
||||
|
||||
|
||||
// What is the name and version of this source tree?
|
||||
#if $[eq $[PACKAGE],]
|
||||
#define PACKAGE pandaapp
|
||||
#define VERSION 0.80
|
||||
#endif
|
||||
|
||||
|
||||
// Where should we find the PANDATOOL source directory?
|
||||
#if $[or $[CTPROJS],$[PANDATOOL]]
|
||||
// If we are presently attached, use the environment variable.
|
||||
#define PANDATOOL_SOURCE $[PANDATOOL]
|
||||
#if $[eq $[PANDATOOL],]
|
||||
#error You seem to be attached to some trees, but not PANDATOOL!
|
||||
#endif
|
||||
#else
|
||||
// Otherwise, if we are not attached, we guess that the source is a
|
||||
// sibling directory to this source root.
|
||||
#define PANDATOOL_SOURCE $[standardize $[TOPDIR]/../pandatool]
|
||||
#endif
|
||||
|
||||
// Where should we install PANDAAPP?
|
||||
#if $[PANDAAPP_INSTALL]
|
||||
#define PANDAAPP_INSTALL $[unixfilename $[PANDAAPP_INSTALL]]
|
||||
#elif $[CTPROJS]
|
||||
#define PANDAAPP_INSTALL $[PANDAAPP]/built
|
||||
#if $[eq $[PANDAAPP],]
|
||||
#error You seem to be attached to some trees, but not PANDAAPP!
|
||||
#endif
|
||||
#else
|
||||
#defer PANDAAPP_INSTALL $[unixfilename $[INSTALL_DIR]]
|
||||
#endif
|
||||
|
||||
// Also get the PANDATOOL Package file and everything that includes.
|
||||
#if $[not $[isfile $[PANDATOOL_SOURCE]/Package.pp]]
|
||||
#printvar PANDATOOL
|
||||
#error PANDATOOL source directory not found from pandaapp! Are you attached properly?
|
||||
#endif
|
||||
|
||||
#include $[PANDATOOL_SOURCE]/Package.pp
|
||||
|
||||
// Define the inter-tree dependencies.
|
||||
#define NEEDS_TREES pandatool $[NEEDS_TREES]
|
||||
#define DEPENDABLE_HEADER_DIRS $[DEPENDABLE_HEADER_DIRS] $[PANDATOOL_INSTALL]/include
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
// This is the toplevel directory. It contains configure.in and other
|
||||
// stuff.
|
||||
|
||||
#define DIR_TYPE toplevel
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
// This is a group directory: a directory level above a number of
|
||||
// source subdirectories.
|
||||
|
||||
#define DIR_TYPE group
|
||||
|
|
@ -1 +0,0 @@
|
|||
#define INSTALL_CONFIG pandaapp.init
|
||||
|
|
@ -1 +0,0 @@
|
|||
ATTACH pandatool
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
#define BUILD_DIRECTORY $[HAVE_OPENSSL]
|
||||
|
||||
#begin bin_target
|
||||
#define TARGET httpbackup
|
||||
#define LOCAL_LIBS pandaappbase
|
||||
#define USE_PACKAGES ssl
|
||||
|
||||
#define OTHER_LIBS \
|
||||
progbase pandatoolbase \
|
||||
express:c downloader:c pandaexpress:m \
|
||||
panda:m dtool:m dtoolconfig:m \
|
||||
pystub
|
||||
|
||||
#define SOURCES \
|
||||
backupCatalog.I backupCatalog.cxx backupCatalog.h \
|
||||
httpBackup.cxx httpBackup.h
|
||||
|
||||
#end bin_target
|
||||
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
// Filename: backupCatalog.I
|
||||
// Created by: drose (29Jan03)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::Entry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE BackupCatalog::Entry::
|
||||
Entry() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::Entry::operator <
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool BackupCatalog::Entry::
|
||||
operator < (const BackupCatalog::Entry &other) const {
|
||||
return get_date() < other.get_date();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::Entry::get_date
|
||||
// Access: Public
|
||||
// Description: Returns the date associated with the entry. This is
|
||||
// the last-modified date provided by the server, if we
|
||||
// have such a thing; or the downloaded date if that's
|
||||
// all we have.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const HTTPDate &BackupCatalog::Entry::
|
||||
get_date() const {
|
||||
return _document_spec.has_date() ? _document_spec.get_date() : _download_date;
|
||||
}
|
||||
|
||||
|
||||
INLINE istream &
|
||||
operator >> (istream &in, BackupCatalog::Entry &entry) {
|
||||
entry.input(in);
|
||||
return in;
|
||||
}
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const BackupCatalog::Entry &entry) {
|
||||
entry.output(out);
|
||||
return out;
|
||||
}
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
// Filename: backupCatalog.cxx
|
||||
// Created by: drose (29Jan03)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "backupCatalog.h"
|
||||
#include "indirectLess.h"
|
||||
#include <algorithm>
|
||||
|
||||
// These are the characters that are not escaped when we write a
|
||||
// filename out to the catalog. Really, the only reason we use
|
||||
// URLSpec::quote() to protect the filenames is to escape spaces.
|
||||
static const char * const acceptable_chars = "~/:";
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BackupCatalog::
|
||||
BackupCatalog() {
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BackupCatalog::
|
||||
~BackupCatalog() {
|
||||
clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::read
|
||||
// Access: Public
|
||||
// Description: Reads the catalog from the named file. Returns true
|
||||
// on success, false on failure. On a false return, the
|
||||
// catalog may have been partially read in.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool BackupCatalog::
|
||||
read(const Filename &filename) {
|
||||
clear();
|
||||
|
||||
ifstream file;
|
||||
if (!filename.open_read(file)) {
|
||||
nout << "Unable to read: " << filename << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
Entry *entry = new Entry;
|
||||
file >> (*entry);
|
||||
while (!file.fail() && !file.eof()) {
|
||||
_table[entry->_document_name].push_back(entry);
|
||||
_filenames.insert(entry->_filename);
|
||||
entry = new Entry;
|
||||
file >> (*entry);
|
||||
}
|
||||
|
||||
// Delete the last Entry that we didn't use.
|
||||
delete entry;
|
||||
|
||||
if (!file.eof()) {
|
||||
// Oops, we had an error on one of the entries.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now sort all of the entries by date.
|
||||
Table::iterator ti;
|
||||
for (ti = _table.begin(); ti != _table.end(); ++ti) {
|
||||
Entries &entries = (*ti).second;
|
||||
sort(entries.begin(), entries.end(), IndirectLess<Entry>());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::write
|
||||
// Access: Public
|
||||
// Description: Rewrites the catalog to the named file. Returns true
|
||||
// on success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool BackupCatalog::
|
||||
write(const Filename &filename) {
|
||||
ofstream file;
|
||||
if (!filename.open_write(file)) {
|
||||
nout << "Unable to write: " << filename << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
Table::const_iterator ti;
|
||||
for (ti = _table.begin(); ti != _table.end(); ++ti) {
|
||||
const Entries &entries = (*ti).second;
|
||||
Entries::const_iterator ei;
|
||||
for (ei = entries.begin(); ei != entries.end(); ++ei) {
|
||||
(*ei)->write(file);
|
||||
file << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (file) {
|
||||
_dirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::clear
|
||||
// Access: Public
|
||||
// Description: Completely empties the contents of the catalog.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void BackupCatalog::
|
||||
clear() {
|
||||
Table::iterator ti;
|
||||
for (ti = _table.begin(); ti != _table.end(); ++ti) {
|
||||
Entries &entries = (*ti).second;
|
||||
Entries::iterator ei;
|
||||
for (ei = entries.begin(); ei != entries.end(); ++ei) {
|
||||
delete (*ei);
|
||||
}
|
||||
}
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::Entry::delete_file
|
||||
// Access: Public
|
||||
// Description: Deletes the file named by the entry, echoing the
|
||||
// indicated reason to nout.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void BackupCatalog::Entry::
|
||||
delete_file(const Filename &dirname, const string &reason) {
|
||||
Filename pathname(dirname, _filename);
|
||||
if (pathname.exists()) {
|
||||
nout << "Deleting " << _filename << " (" << reason << ").\n";
|
||||
if (!pathname.unlink()) {
|
||||
nout << "unable to delete.\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
nout << "Tried to delete " << _filename << " but it's already gone!\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::Entry::input
|
||||
// Access: Public
|
||||
// Description: Can be used to read in the catalog entry from a
|
||||
// stream generated by either output() or write().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void BackupCatalog::Entry::
|
||||
input(istream &in) {
|
||||
in >> _document_name >> _filename >> _document_spec >> _download_date;
|
||||
_document_name = URLSpec::unquote(_document_name);
|
||||
_filename = URLSpec::unquote(_filename);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::Entry::output
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void BackupCatalog::Entry::
|
||||
output(ostream &out) const {
|
||||
out << URLSpec::quote(_document_name, acceptable_chars) << " "
|
||||
<< URLSpec::quote(_filename, acceptable_chars) << " "
|
||||
<< _document_spec << " "
|
||||
<< _download_date;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BackupCatalog::Entry::write
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void BackupCatalog::Entry::
|
||||
write(ostream &out) const {
|
||||
out << URLSpec::quote(_document_name, acceptable_chars) << " "
|
||||
<< URLSpec::quote(_filename, acceptable_chars) << "\n";
|
||||
_document_spec.write(out, 2);
|
||||
out << " " << _download_date << "\n";
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// Filename: backupCatalog.h
|
||||
// Created by: drose (29Jan03)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BACKUPCATALOG_H
|
||||
#define BACKUPCATALOG_H
|
||||
|
||||
#include "pandaappbase.h"
|
||||
|
||||
#include "documentSpec.h"
|
||||
#include "filename.h"
|
||||
#include "pvector.h"
|
||||
#include "pmap.h"
|
||||
#include "pset.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : BackupCatalog
|
||||
// Description : This is the list of previous versions of this file
|
||||
// (and possibly other files) stored in the "catalog", a
|
||||
// text file within the download directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class BackupCatalog {
|
||||
public:
|
||||
BackupCatalog();
|
||||
~BackupCatalog();
|
||||
|
||||
bool read(const Filename &filename);
|
||||
bool write(const Filename &filename);
|
||||
void clear();
|
||||
|
||||
class Entry {
|
||||
public:
|
||||
INLINE Entry();
|
||||
INLINE bool operator < (const Entry &other) const;
|
||||
INLINE const HTTPDate &get_date() const;
|
||||
|
||||
void delete_file(const Filename &dirname, const string &reason);
|
||||
void input(istream &in);
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out) const;
|
||||
|
||||
string _document_name;
|
||||
string _filename;
|
||||
DocumentSpec _document_spec;
|
||||
HTTPDate _download_date;
|
||||
};
|
||||
|
||||
typedef pvector<Entry *> Entries;
|
||||
typedef pmap<string, Entries> Table;
|
||||
Table _table;
|
||||
|
||||
typedef pset<string> Filenames;
|
||||
Filenames _filenames;
|
||||
|
||||
bool _dirty;
|
||||
};
|
||||
|
||||
INLINE istream &operator >> (istream &in, BackupCatalog::Entry &entry);
|
||||
INLINE ostream &operator << (ostream &out, const BackupCatalog::Entry &entry);
|
||||
|
||||
#include "backupCatalog.I"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,519 +0,0 @@
|
|||
// Filename: httpBackup.cxx
|
||||
// Created by: drose (29Jan03)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "httpBackup.h"
|
||||
#include "httpChannel.h"
|
||||
|
||||
|
||||
static const int seconds_per_day = 60 * 60 * 24;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPBackup::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HTTPBackup::
|
||||
HTTPBackup() {
|
||||
clear_runlines();
|
||||
add_runline("[opts] url");
|
||||
add_runline("-check <days> url");
|
||||
|
||||
set_program_description
|
||||
("This program is designed to run periodically as a "
|
||||
"background task, e.g. via a cron job. It fetches the "
|
||||
"latest copy of a document from an HTTP server and "
|
||||
"stores it, along with an optional number of previous "
|
||||
"versions, in a local directory so that it may be "
|
||||
"backed up to tape.\n\n"
|
||||
|
||||
"If the copy on disk is already the same as the latest "
|
||||
"copy available on the HTTP server, this program generally "
|
||||
"does nothing (although it may delete old versions if they "
|
||||
"have expired past the maximum age specified on the command "
|
||||
"line).");
|
||||
|
||||
add_option
|
||||
("p", "url", 0,
|
||||
"Specifies the URL of the HTTP proxy server(s), if one is required. "
|
||||
"Multiple servers may be specified by separating them with semicolons; "
|
||||
"they will be tried in the order listed.",
|
||||
&HTTPBackup::dispatch_string, &_got_proxy, &_proxy);
|
||||
|
||||
add_option
|
||||
("a", "", 0,
|
||||
"If this option is specified, the document is always downloaded every "
|
||||
"time httpbackup runs, even if the document does not appear to have "
|
||||
"been changed since last time.",
|
||||
&HTTPBackup::dispatch_none, &_always_download, NULL);
|
||||
|
||||
add_option
|
||||
("d", "dirname", 0,
|
||||
"Specifies the name of the directory in which to store the backup "
|
||||
"versions of the document. The default is '.', the current "
|
||||
"directory.",
|
||||
&HTTPBackup::dispatch_filename, NULL, &_dirname);
|
||||
|
||||
add_option
|
||||
("c", "filename", 0,
|
||||
"Specifies the name of the catalog file that httpbackup uses to "
|
||||
"record the HTTP entity tags, etc., downloaded from previous "
|
||||
"versions. If a relative filename is given, it is relative to "
|
||||
"the directory specified by -d. The default is 'Catalog'.",
|
||||
&HTTPBackup::dispatch_filename, NULL, &_catalog_name);
|
||||
|
||||
add_option
|
||||
("n", "filename", 0,
|
||||
"Specifies the name of the document that is being retrieved. This "
|
||||
"name is written to the catalog file to identify entries for this "
|
||||
"document, and is used to generate the filename to store the "
|
||||
"backup versions. The default if this is omitted or empty is to use "
|
||||
"the basename of the URL.",
|
||||
&HTTPBackup::dispatch_string, NULL, &_document_name);
|
||||
|
||||
add_option
|
||||
("s", "string", 0,
|
||||
"Specifies how the date is appended onto the filename (see -n) for "
|
||||
"each version of the file. This string should contain the sequence "
|
||||
"of characters from strftime() that correspond to the desired date "
|
||||
"format to append to the filename. The default is '.%Y-%m-%d.%H-%M', "
|
||||
"or the year, month, day, hour, and minute. (The date is always "
|
||||
"represented in GMT, according to HTTP convention.)",
|
||||
&HTTPBackup::dispatch_string, NULL, &_version_append);
|
||||
|
||||
add_option
|
||||
("maxage", "days", 0,
|
||||
"Specifies the maximum age, in days, to keep an old version of the "
|
||||
"file around. If unspecified, the default is no limit. This may "
|
||||
"be a floating-point number.",
|
||||
&HTTPBackup::dispatch_double, &_got_max_keep_days, &_max_keep_days);
|
||||
|
||||
add_option
|
||||
("minage", "days", 0,
|
||||
"Specifies the minimum age, in days, an old version of the file must "
|
||||
"have before it is automatically deleted due to exceeding -maxver. "
|
||||
"The default is 0. This may be a floating-point number.",
|
||||
&HTTPBackup::dispatch_double, NULL, &_min_keep_days);
|
||||
|
||||
add_option
|
||||
("maxver", "count", 0,
|
||||
"Specifies the maximum number of old versions of the file to keep "
|
||||
"around. If unspecified, the default is no limit.",
|
||||
&HTTPBackup::dispatch_int, &_got_max_keep_versions, &_max_keep_versions);
|
||||
|
||||
add_option
|
||||
("minver", "count", 0,
|
||||
"Specifies the minimum number of old versions to keep after "
|
||||
"deleting versions older than -maxage. The default is 1.",
|
||||
&HTTPBackup::dispatch_int, NULL, &_min_keep_versions);
|
||||
|
||||
add_option
|
||||
("check", "days", 0,
|
||||
"Instead of downloading any document, check the date of the most recent "
|
||||
"document downloaded. Returns success if that date is no more than the "
|
||||
"indicated number of days old (which may be a floating-point number), "
|
||||
"or failure otherwise.",
|
||||
&HTTPBackup::dispatch_double, &_got_check_days, &_check_days);
|
||||
|
||||
_dirname = ".";
|
||||
_catalog_name = "Catalog";
|
||||
_version_append = ".%Y-%m-%d.%H-%M";
|
||||
_max_keep_days = 0.0;
|
||||
_min_keep_days = 0.0;
|
||||
_max_keep_versions = 0;
|
||||
_min_keep_versions = 1;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPBackup::handle_args
|
||||
// Access: Protected, Virtual
|
||||
// Description: Does something with the additional arguments on the
|
||||
// command line (after all the -options have been
|
||||
// parsed). Returns true if the arguments are good,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPBackup::
|
||||
handle_args(ProgramBase::Args &args) {
|
||||
if (_got_check_days && !_document_name.empty() && args.empty()) {
|
||||
// If -check and -n are both specified, we don't really need to
|
||||
// specify an URL. Accept it if we don't.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.size() != 1) {
|
||||
nout <<
|
||||
"You must specify the URL of the document to download "
|
||||
"on the command line.\n\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
_url = URLSpec(args[0]);
|
||||
if (!(_url.has_server() && _url.has_path())) {
|
||||
nout
|
||||
<< "Invalid URL specification: " << args[0] << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPBackup::post_command_line
|
||||
// Access: Protected, Virtual
|
||||
// Description: This is called after the command line has been
|
||||
// completely processed, and it gives the program a
|
||||
// chance to do some last-minute processing and
|
||||
// validation of the options and arguments. It should
|
||||
// return true if everything is fine, false if there is
|
||||
// an error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPBackup::
|
||||
post_command_line() {
|
||||
if (_got_proxy) {
|
||||
_http.set_proxy_spec(_proxy);
|
||||
}
|
||||
|
||||
if (!_catalog_name.is_fully_qualified()) {
|
||||
_catalog_name = Filename(_dirname, _catalog_name);
|
||||
}
|
||||
|
||||
if (_document_name.empty()) {
|
||||
Filename pathname = _url.get_path();
|
||||
_document_name = pathname.get_basename();
|
||||
}
|
||||
|
||||
if (_min_keep_days < 0.0) {
|
||||
nout << "Invalid -minage " << _min_keep_days << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_min_keep_versions < 0) {
|
||||
nout << "Invalid -minver " << _min_keep_versions << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_got_max_keep_days) {
|
||||
if (_max_keep_days < _min_keep_days) {
|
||||
nout
|
||||
<< "-maxage " << _max_keep_days << " is less than -minage "
|
||||
<< _min_keep_days << "\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_got_max_keep_versions) {
|
||||
if (_max_keep_versions < _min_keep_versions) {
|
||||
nout
|
||||
<< "-maxver " << _max_keep_versions << " is less than -minver "
|
||||
<< _min_keep_versions << "\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_now = HTTPDate::now();
|
||||
if (_got_max_keep_days) {
|
||||
_max_keep_date = _now - (time_t)(_max_keep_days * seconds_per_day);
|
||||
}
|
||||
_min_keep_date = _now - (time_t)(_min_keep_days * seconds_per_day);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPBackup::dispatch_url
|
||||
// Access: Protected, Static
|
||||
// Description: Dispatch function for a URL parameter.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPBackup::
|
||||
dispatch_url(const string &opt, const string &arg, void *var) {
|
||||
URLSpec *up = (URLSpec *)var;
|
||||
URLSpec new_url(arg);
|
||||
(*up) = new_url;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPBackup::run
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HTTPBackup::
|
||||
run() {
|
||||
// Output the current date and time in GMT, for logging.
|
||||
nout << _now.get_string() << "\n";
|
||||
|
||||
// First, read in the catalog.
|
||||
_catalog_name.set_text();
|
||||
if (!_catalog_name.exists()) {
|
||||
nout << _catalog_name << " does not yet exist.\n";
|
||||
} else {
|
||||
if (!_catalog.read(_catalog_name)) {
|
||||
nout << "Unable to read " << _catalog_name << ".\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (_got_check_days) {
|
||||
// We're only checking the date of the latest download.
|
||||
BackupCatalog::Entries &entries = _catalog._table[_document_name];
|
||||
if (entries.empty()) {
|
||||
nout << "No previous downloads for " << _document_name << ".\n";
|
||||
exit(1);
|
||||
}
|
||||
BackupCatalog::Entry *latest = entries[entries.size() - 1];
|
||||
int diff_secs = _now - latest->get_date();
|
||||
double diff_days = (double)diff_secs / (double)seconds_per_day;
|
||||
nout << "Most recent at " << latest->get_date().get_string()
|
||||
<< ", " << diff_days << " days old.\n";
|
||||
if (diff_days <= _check_days) {
|
||||
nout << "OK.\n";
|
||||
} else {
|
||||
nout << "Too old!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Try to do the download.
|
||||
|
||||
// Now try to fetch the document.
|
||||
if (!fetch_latest()) {
|
||||
nout << "Errors while processing latest.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!cleanup_old()) {
|
||||
nout << "Errors while cleaning up old versions.\n";
|
||||
// We don't bother to exit the program in this case.
|
||||
}
|
||||
|
||||
if (_catalog._dirty) {
|
||||
// Now write out the modified catalog.
|
||||
nout << "Writing " << _catalog_name << "\n";
|
||||
_catalog_name.make_dir();
|
||||
if (!_catalog.write(_catalog_name)) {
|
||||
nout << "Unable to rewrite " << _catalog_name << ".\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPBackup::fetch_latest
|
||||
// Access: Private
|
||||
// Description: Tries to get the latest version of the document from
|
||||
// the server, if there is one available. Returns true
|
||||
// on success (even if the most recent document hasn't
|
||||
// changed), or false if there was some error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPBackup::
|
||||
fetch_latest() {
|
||||
// Check the most recent version of this document.
|
||||
BackupCatalog::Entries &entries = _catalog._table[_document_name];
|
||||
|
||||
DocumentSpec document_spec(_url);
|
||||
if (!entries.empty()) {
|
||||
BackupCatalog::Entry *latest = entries[entries.size() - 1];
|
||||
document_spec = latest->_document_spec;
|
||||
document_spec.set_url(_url);
|
||||
if (!document_spec.has_date()) {
|
||||
// If we didn't get a last-modified date, use the download date
|
||||
// instead.
|
||||
document_spec.set_date(latest->get_date());
|
||||
}
|
||||
if (!_always_download) {
|
||||
document_spec.set_request_mode(DocumentSpec::RM_newer);
|
||||
}
|
||||
}
|
||||
|
||||
// Since the purpose of this program is to check to see if a more
|
||||
// recent document is available, we probably always want any proxies
|
||||
// in the way to revalidate their cache.
|
||||
document_spec.set_cache_control(DocumentSpec::CC_revalidate);
|
||||
|
||||
if (document_spec.get_request_mode() == DocumentSpec::RM_newer &&
|
||||
document_spec.has_date()) {
|
||||
nout << "Checking for newer than "<< document_spec.get_date().get_string()
|
||||
<< ".\n";
|
||||
}
|
||||
nout << "Fetching " << document_spec.get_url() << "\n";
|
||||
|
||||
PT(HTTPChannel) channel = _http.make_channel(true);
|
||||
if (_always_download) {
|
||||
channel->get_document(document_spec);
|
||||
} else {
|
||||
// Start out by asking for the header first, so we can verify the
|
||||
// document has changed before we try to download it again.
|
||||
channel->get_header(document_spec);
|
||||
}
|
||||
|
||||
if (!channel->is_valid()) {
|
||||
if (channel->get_status_code() == 304) {
|
||||
nout << "Document has not been modified.\n";
|
||||
// This is considered a success condition.
|
||||
return true;
|
||||
}
|
||||
nout << "Error fetching document: " << channel->get_status_code()
|
||||
<< " " << channel->get_status_string() << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// The document is available.
|
||||
if (!_always_download) {
|
||||
if (!entries.empty()) {
|
||||
// Has it been modified? We need to check again because the
|
||||
// If-None-Match fields, etc. might have been ignored (e.g. by a
|
||||
// proxy).
|
||||
if (document_spec == channel->get_document_spec()) {
|
||||
nout
|
||||
<< "Document has not been modified (server ignored conditional request).\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Ok, the document really is ready. Go ahead and download it.
|
||||
if (!channel->get_document(document_spec)) {
|
||||
nout << "Unable to request document.\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We've started to download the document. Create an entry for it.
|
||||
BackupCatalog::Entry *entry = new BackupCatalog::Entry;
|
||||
entry->_document_name = _document_name;
|
||||
entry->_document_spec = channel->get_document_spec();
|
||||
entry->_download_date = _now;
|
||||
|
||||
// Generate a filename based on the last-modified date or the
|
||||
// download date.
|
||||
time_t time = entry->get_date().get_time();
|
||||
struct tm *tp = gmtime(&time);
|
||||
|
||||
static const int buffer_size = 512;
|
||||
char buffer[buffer_size];
|
||||
if (strftime(buffer, buffer_size, _version_append.c_str(), tp) == 0) {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
|
||||
string filename = _document_name + string(buffer);
|
||||
|
||||
// Check the filename for uniqueness, just for good measure.
|
||||
check_unique(filename);
|
||||
|
||||
entry->_filename = filename;
|
||||
|
||||
// Download to the indicated filename.
|
||||
Filename pathname(_dirname, filename);
|
||||
nout << "Downloading to " << pathname << "\n";
|
||||
pathname.make_dir();
|
||||
if (!channel->download_to_file(pathname)) {
|
||||
nout << "Error while downloading.\n";
|
||||
delete entry;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The file is successfully downloaded; save the entry.
|
||||
entries.push_back(entry);
|
||||
_catalog._dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPBackup::cleanup_old
|
||||
// Access: Private
|
||||
// Description: Removes old versions that are no longer needed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPBackup::
|
||||
cleanup_old() {
|
||||
BackupCatalog::Entries &entries = _catalog._table[_document_name];
|
||||
|
||||
if (_got_max_keep_versions &&
|
||||
(int)entries.size() > _max_keep_versions) {
|
||||
// Too many versions; delete the oldest ones, except those newer
|
||||
// than min_keep_date.
|
||||
int num_delete = entries.size() - _max_keep_versions;
|
||||
while (num_delete > 0 && entries[num_delete - 1]->get_date() > _min_keep_date) {
|
||||
num_delete--;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_delete; i++) {
|
||||
entries[i]->delete_file(_dirname, "too many old versions");
|
||||
delete entries[i];
|
||||
}
|
||||
entries.erase(entries.begin(), entries.begin() + num_delete);
|
||||
_catalog._dirty = true;
|
||||
}
|
||||
|
||||
if (_got_max_keep_days &&
|
||||
(int)entries.size() > _min_keep_versions &&
|
||||
entries[0]->get_date() < _max_keep_date) {
|
||||
// The oldest version is too old; delete all the oldest ones,
|
||||
// but keep at least min_keep_versions of them around.
|
||||
int num_delete = 1;
|
||||
while (num_delete < (int)entries.size() - _min_keep_versions &&
|
||||
entries[num_delete]->get_date() < _max_keep_date) {
|
||||
num_delete++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_delete; i++) {
|
||||
entries[i]->delete_file(_dirname, "too old");
|
||||
delete entries[i];
|
||||
}
|
||||
entries.erase(entries.begin(), entries.begin() + num_delete);
|
||||
_catalog._dirty = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPBackup::check_unique
|
||||
// Access: Private
|
||||
// Description: Ensures that the given filename is unique among all
|
||||
// files in the catalog.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HTTPBackup::
|
||||
check_unique(string &filename) {
|
||||
bool inserted = _catalog._filenames.insert(filename).second;
|
||||
|
||||
if (!inserted) {
|
||||
// Conflict; append one or more letters to the filename until it
|
||||
// is unique.
|
||||
unsigned int uniquifier = 1;
|
||||
string orig_filename = filename;
|
||||
orig_filename += '.';
|
||||
|
||||
while (!inserted) {
|
||||
filename = orig_filename;
|
||||
|
||||
unsigned int count = uniquifier;
|
||||
while (count > 0) {
|
||||
char ch = (char)((count % 26) + 'a');
|
||||
filename += ch;
|
||||
count /= 26;
|
||||
}
|
||||
|
||||
uniquifier++;
|
||||
inserted = _catalog._filenames.insert(filename).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
HTTPBackup prog;
|
||||
prog.parse_command_line(argc, argv);
|
||||
prog.run();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
// Filename: httpBackup.h
|
||||
// Created by: drose (29Jan03)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef HTTPBACKUP_H
|
||||
#define HTTPBACKUP_H
|
||||
|
||||
#include "pandaappbase.h"
|
||||
#include "programBase.h"
|
||||
#include "backupCatalog.h"
|
||||
|
||||
#include "httpClient.h"
|
||||
#include "urlSpec.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : HTTPBackup
|
||||
// Description : This program is designed to run periodically as a
|
||||
// background task, e.g. via a cron job. It fetches the
|
||||
// latest copy of a document from an HTTP server and
|
||||
// stores it, along with an optional number of previous
|
||||
// versions, in a local directory so that it may be
|
||||
// backed up to tape.
|
||||
//
|
||||
// If the copy on disk is already the same as the latest
|
||||
// copy available on the HTTP server, this program does
|
||||
// nothing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class HTTPBackup : public ProgramBase {
|
||||
public:
|
||||
HTTPBackup();
|
||||
|
||||
protected:
|
||||
virtual bool handle_args(Args &args);
|
||||
virtual bool post_command_line();
|
||||
|
||||
static bool dispatch_url(const string &opt, const string &arg, void *var);
|
||||
|
||||
public:
|
||||
void run();
|
||||
|
||||
private:
|
||||
bool fetch_latest();
|
||||
bool cleanup_old();
|
||||
void check_unique(string &filename);
|
||||
|
||||
private:
|
||||
string _proxy;
|
||||
bool _got_proxy;
|
||||
|
||||
URLSpec _url;
|
||||
Filename _dirname;
|
||||
Filename _catalog_name;
|
||||
string _document_name;
|
||||
string _version_append;
|
||||
bool _always_download;
|
||||
|
||||
double _max_keep_days;
|
||||
bool _got_max_keep_days;
|
||||
double _min_keep_days;
|
||||
int _max_keep_versions;
|
||||
bool _got_max_keep_versions;
|
||||
int _min_keep_versions;
|
||||
double _check_days;
|
||||
bool _got_check_days;
|
||||
|
||||
HTTPDate _max_keep_date;
|
||||
HTTPDate _min_keep_date;
|
||||
HTTPDate _now;
|
||||
|
||||
HTTPClient _http;
|
||||
BackupCatalog _catalog;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#define BUILD_DIRECTORY $[HAVE_FREETYPE]
|
||||
|
||||
#define OTHER_LIBS \
|
||||
progbase pandatoolbase \
|
||||
dtoolutil:c dtool:m prc:c dtoolbase:c dtoolconfig:m \
|
||||
express:c pandaexpress:m \
|
||||
putil:c pipeline:c linmath:c pnmimage:c mathutil:c pnmtext:c \
|
||||
pnmimagetypes:c event:c panda:m \
|
||||
pystub
|
||||
|
||||
#define UNIX_SYS_LIBS dl
|
||||
|
||||
#begin bin_target
|
||||
#define USE_PACKAGES freetype
|
||||
|
||||
#define TARGET indexify
|
||||
|
||||
#define SOURCES \
|
||||
default_index_icons.cxx default_index_icons.h \
|
||||
default_font.cxx default_font.h \
|
||||
indexImage.cxx indexImage.h \
|
||||
indexParameters.cxx indexParameters.h \
|
||||
indexify.cxx indexify.h \
|
||||
photo.cxx photo.h \
|
||||
rollDirectory.cxx rollDirectory.h
|
||||
|
||||
#end bin_target
|
||||
|
||||
#begin bin_target
|
||||
#define USE_PACKAGES freetype
|
||||
|
||||
#define TARGET font-samples
|
||||
|
||||
#define SOURCES \
|
||||
default_font.cxx default_font.h \
|
||||
fontSamples.cxx fontSamples.h
|
||||
|
||||
#end bin_target
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,22 +0,0 @@
|
|||
// Filename: default_font.h
|
||||
// Created by: drose (04Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef DEFAULT_FONT_H
|
||||
#define DEFAULT_FONT_H
|
||||
|
||||
extern const unsigned char default_font[];
|
||||
extern const int default_font_size;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,297 +0,0 @@
|
|||
// Filename: default_index_icons.cxx
|
||||
// Created by: drose (04Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "default_index_icons.h"
|
||||
|
||||
// This file was generated from left.png, right.png, up.png,
|
||||
// movie.png, and sound.png; it provides data for default icons if the
|
||||
// -i parameter is supplied on the command line.
|
||||
|
||||
const char *default_left_icon_filename = "left.png";
|
||||
const char *default_right_icon_filename = "right.png";
|
||||
const char *default_up_icon_filename = "up.png";
|
||||
const char *default_movie_icon_filename = "movie.png";
|
||||
const char *default_sound_icon_filename = "sound.png";
|
||||
|
||||
/*
|
||||
|
||||
Use this series of commands to regenerate the tables:
|
||||
|
||||
bin2c -n default_left_icon left.png >> default_index_icons.cxx
|
||||
bin2c -n default_right_icon right.png >> default_index_icons.cxx
|
||||
bin2c -n default_up_icon up.png >> default_index_icons.cxx
|
||||
bin2c -n default_movie_icon movie.png >> default_index_icons.cxx
|
||||
bin2c -n default_sound_icon sound.png >> default_index_icons.cxx
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* This table was generated by the command:
|
||||
*
|
||||
* bin2c -n default_left_icon left.png
|
||||
*/
|
||||
|
||||
const unsigned char default_left_icon[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
|
||||
0x00, 0x1e, 0x08, 0x03, 0x00, 0x00, 0x00, 0x0c, 0xee, 0x5e, 0x90,
|
||||
0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1,
|
||||
0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x2d, 0x50, 0x4c,
|
||||
0x54, 0x45, 0xeb, 0xed, 0xee, 0xdd, 0xe1, 0xe3, 0xcf, 0xd4, 0xd7,
|
||||
0xc2, 0xc9, 0xcd, 0xb5, 0xbd, 0xc2, 0xae, 0xb7, 0xbc, 0xa7, 0xb0,
|
||||
0xb6, 0x99, 0xa4, 0xab, 0x8c, 0x98, 0xa0, 0x7e, 0x8c, 0x95, 0x77,
|
||||
0x86, 0x8f, 0x6c, 0x7a, 0x83, 0x60, 0x6c, 0x74, 0x55, 0x60, 0x67,
|
||||
0x4f, 0x5a, 0x60, 0x44, 0x10, 0xa7, 0xee, 0x00, 0x00, 0x01, 0x96,
|
||||
0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x7d, 0x93, 0xdd, 0x92, 0xec,
|
||||
0x20, 0x08, 0x84, 0x47, 0x7e, 0x04, 0xd4, 0xe4, 0xfd, 0x1f, 0xf7,
|
||||
0x74, 0xe3, 0x9c, 0xaa, 0xbd, 0xd8, 0x5a, 0x2f, 0x66, 0x12, 0x3f,
|
||||
0x81, 0xb6, 0x21, 0x9f, 0xcf, 0x2f, 0x4b, 0xe4, 0xfb, 0x70, 0x7e,
|
||||
0xa3, 0x9f, 0x31, 0xee, 0xff, 0x24, 0x56, 0x15, 0x8b, 0xa9, 0x63,
|
||||
0x08, 0x96, 0xe9, 0xf8, 0x0c, 0x35, 0x9f, 0xa6, 0xa2, 0xb5, 0x89,
|
||||
0x45, 0x67, 0xba, 0xca, 0x10, 0x33, 0x73, 0x13, 0x9c, 0x53, 0x2e,
|
||||
0xb3, 0x45, 0x6c, 0x86, 0x27, 0x1c, 0xc6, 0x29, 0x47, 0x26, 0xe2,
|
||||
0x7e, 0x33, 0xad, 0x02, 0x8e, 0x00, 0x9d, 0xd3, 0xb8, 0x21, 0x0c,
|
||||
0x14, 0x3b, 0xce, 0x42, 0xa3, 0x16, 0x05, 0x4c, 0x77, 0xc7, 0x19,
|
||||
0x60, 0x63, 0xca, 0xb9, 0x9f, 0x07, 0x69, 0x20, 0x26, 0xd7, 0x95,
|
||||
0xa6, 0xea, 0xdc, 0x40, 0x65, 0xf3, 0x7a, 0xdf, 0xe7, 0xa0, 0x1e,
|
||||
0xb4, 0xcc, 0x6c, 0x69, 0x54, 0x3c, 0xad, 0x57, 0x3e, 0x58, 0xa7,
|
||||
0xb1, 0x68, 0x54, 0x47, 0xb3, 0xa4, 0xff, 0x80, 0x7b, 0xb7, 0x46,
|
||||
0xcd, 0xfc, 0x62, 0xe4, 0x45, 0x81, 0xf3, 0x36, 0x5c, 0x6b, 0x07,
|
||||
0x6f, 0xe6, 0x19, 0xc4, 0x14, 0x84, 0x3b, 0xd5, 0x83, 0xa2, 0x7b,
|
||||
0xef, 0xca, 0x5c, 0xd1, 0x2a, 0xcf, 0xba, 0xf7, 0x86, 0xde, 0x42,
|
||||
0xda, 0xf7, 0x41, 0x64, 0x55, 0x56, 0x39, 0xb2, 0x89, 0x1e, 0x9a,
|
||||
0xea, 0x6e, 0x1a, 0xcc, 0x4b, 0x0c, 0x08, 0xba, 0x9c, 0x29, 0x75,
|
||||
0x37, 0x06, 0x7d, 0xbb, 0xea, 0x73, 0x16, 0x28, 0x70, 0xb5, 0x91,
|
||||
0xd6, 0xd1, 0xbc, 0x17, 0xac, 0xa0, 0x60, 0x64, 0x66, 0x74, 0x26,
|
||||
0x5d, 0xd6, 0x9b, 0x9c, 0x1d, 0x10, 0x49, 0x62, 0x42, 0xe2, 0x0a,
|
||||
0x52, 0x59, 0xed, 0x1a, 0xcc, 0x62, 0xae, 0xd8, 0x0c, 0xcf, 0x3e,
|
||||
0x10, 0x74, 0xf2, 0xde, 0xdb, 0x33, 0xd9, 0x14, 0x38, 0x57, 0x67,
|
||||
0xdf, 0xec, 0x3b, 0x18, 0xe0, 0xbb, 0x5b, 0x12, 0xc0, 0xd7, 0xd9,
|
||||
0x80, 0xe8, 0x95, 0x51, 0x3b, 0x69, 0xe2, 0xad, 0xad, 0x16, 0x41,
|
||||
0xda, 0xdd, 0x44, 0x85, 0x8a, 0x2c, 0x36, 0xd1, 0xa4, 0x1b, 0x0a,
|
||||
0xbf, 0x1d, 0xed, 0x61, 0x13, 0xc4, 0xdc, 0x29, 0x3c, 0x31, 0x4d,
|
||||
0xae, 0x63, 0x4e, 0x46, 0x63, 0xb0, 0xe4, 0x36, 0x5b, 0x67, 0xc0,
|
||||
0xfb, 0xeb, 0x1a, 0x42, 0x26, 0x3d, 0x97, 0x89, 0xdc, 0x18, 0x17,
|
||||
0x12, 0x4e, 0x05, 0x86, 0x6a, 0xb9, 0xd0, 0xd5, 0x6c, 0x5b, 0xa8,
|
||||
0x0b, 0xd9, 0x48, 0xfa, 0xc7, 0xfe, 0xcf, 0xe5, 0x6a, 0x7c, 0x27,
|
||||
0x8c, 0x9b, 0x82, 0xa1, 0x31, 0xef, 0xa9, 0x1e, 0xa8, 0xb9, 0xf7,
|
||||
0xd7, 0xd4, 0x56, 0xae, 0x2d, 0xa0, 0xa7, 0xb2, 0xa5, 0x7e, 0x3d,
|
||||
0xff, 0x33, 0x7a, 0xf6, 0x45, 0xe1, 0xdc, 0x84, 0x3a, 0x98, 0xb6,
|
||||
0xcf, 0xc2, 0x0b, 0xac, 0xa1, 0x03, 0xf8, 0xcc, 0xce, 0x69, 0xa3,
|
||||
0x89, 0xc9, 0xd1, 0x9a, 0xc0, 0x73, 0x9e, 0x8d, 0xad, 0x7f, 0xbd,
|
||||
0xcf, 0x11, 0xe9, 0xc6, 0x04, 0xc1, 0x3d, 0x00, 0x00, 0x00, 0x00,
|
||||
0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
|
||||
};
|
||||
|
||||
const int default_left_icon_len = 536;
|
||||
|
||||
|
||||
/*
|
||||
* This table was generated by the command:
|
||||
*
|
||||
* bin2c -n default_right_icon right.png
|
||||
*/
|
||||
|
||||
const unsigned char default_right_icon[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
|
||||
0x00, 0x1e, 0x08, 0x03, 0x00, 0x00, 0x00, 0x0c, 0xee, 0x5e, 0x90,
|
||||
0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1,
|
||||
0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x2d, 0x50, 0x4c,
|
||||
0x54, 0x45, 0xec, 0xee, 0xef, 0xd8, 0xdc, 0xdf, 0xca, 0xd0, 0xd3,
|
||||
0xc3, 0xc9, 0xcd, 0xae, 0xb7, 0xbc, 0xa8, 0xb1, 0xb7, 0x99, 0xa4,
|
||||
0xab, 0x93, 0x9f, 0xa6, 0x86, 0x93, 0x9b, 0x77, 0x86, 0x8f, 0x71,
|
||||
0x80, 0x89, 0x60, 0x6c, 0x74, 0x5b, 0x67, 0x6e, 0x50, 0x5b, 0x61,
|
||||
0x45, 0x4e, 0x53, 0xeb, 0x64, 0x46, 0x0c, 0x00, 0x00, 0x01, 0x8c,
|
||||
0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0x92, 0x59, 0x6e, 0xc3,
|
||||
0x30, 0x0c, 0x44, 0x2d, 0x71, 0x95, 0x94, 0xf4, 0xfe, 0xc7, 0xed,
|
||||
0xcc, 0xc8, 0x40, 0x7f, 0x4a, 0x04, 0x89, 0xc3, 0xc7, 0x65, 0x4c,
|
||||
0xf2, 0x79, 0xfe, 0xb1, 0x39, 0xde, 0x87, 0xf3, 0xfc, 0x6b, 0x2f,
|
||||
0x0e, 0xe2, 0x69, 0xd3, 0x6c, 0xce, 0x31, 0xf8, 0xc1, 0xef, 0x33,
|
||||
0x3c, 0x33, 0xc3, 0xe7, 0x58, 0x1b, 0x18, 0xc8, 0x33, 0x8c, 0x6c,
|
||||
0x20, 0x14, 0x99, 0xd3, 0x3d, 0x1c, 0x6e, 0x61, 0x64, 0x44, 0x05,
|
||||
0x53, 0xdd, 0xcd, 0x6d, 0xa8, 0xde, 0x44, 0x45, 0x5b, 0x0d, 0x0c,
|
||||
0xa7, 0x79, 0x7d, 0x62, 0x98, 0x52, 0xc6, 0x20, 0x1e, 0xc2, 0x0b,
|
||||
0x38, 0x13, 0xbc, 0x7f, 0xbe, 0x1b, 0x71, 0x72, 0x8f, 0x71, 0x45,
|
||||
0x8c, 0x22, 0x8e, 0x70, 0xf7, 0xf5, 0xf3, 0xfd, 0x7c, 0xda, 0x21,
|
||||
0x03, 0x32, 0x81, 0xf9, 0xfd, 0x44, 0xdf, 0xde, 0xd3, 0xfa, 0xfb,
|
||||
0x39, 0xb0, 0x36, 0xbe, 0x86, 0x5d, 0x8d, 0x23, 0x97, 0x94, 0xa3,
|
||||
0x56, 0x01, 0xef, 0x7d, 0xce, 0x4e, 0x89, 0x12, 0xb6, 0x62, 0xb6,
|
||||
0xa2, 0xf3, 0x0b, 0x4a, 0x3b, 0xcb, 0xe9, 0xa0, 0x78, 0xeb, 0x7c,
|
||||
0x31, 0xb2, 0xcf, 0x5e, 0xb2, 0x7d, 0xca, 0x5c, 0x21, 0x7e, 0x54,
|
||||
0x9c, 0x73, 0xe9, 0xef, 0x21, 0xeb, 0x06, 0xdf, 0xbb, 0x9d, 0x6f,
|
||||
0xe1, 0xe7, 0xdc, 0x6c, 0xb3, 0x22, 0x86, 0xbf, 0x5a, 0x05, 0x76,
|
||||
0x72, 0x04, 0xfb, 0xdc, 0xb1, 0xcc, 0x99, 0xc4, 0x50, 0x5e, 0x85,
|
||||
0x02, 0x94, 0x90, 0xc8, 0x39, 0x17, 0x73, 0xac, 0x12, 0xbe, 0xbb,
|
||||
0x6f, 0x7e, 0xb3, 0xf9, 0xc5, 0x9a, 0x91, 0x13, 0x93, 0xca, 0x5c,
|
||||
0xe2, 0xa6, 0x86, 0xaa, 0x55, 0x09, 0xaf, 0x0b, 0xcb, 0x4c, 0x0d,
|
||||
0x67, 0xd5, 0xa3, 0xf5, 0xf9, 0xed, 0xbd, 0x29, 0x9d, 0x4d, 0x45,
|
||||
0xcd, 0x36, 0xb3, 0xbd, 0x2a, 0xa1, 0x9c, 0xaf, 0x8d, 0xfc, 0xd0,
|
||||
0xfa, 0x5d, 0x31, 0xea, 0x1d, 0x59, 0xe9, 0xf9, 0x01, 0x5a, 0x2b,
|
||||
0xe1, 0xc4, 0x34, 0x71, 0x2b, 0xec, 0xdd, 0x4b, 0xc5, 0x33, 0x2d,
|
||||
0x0e, 0x87, 0x31, 0x4d, 0x58, 0x3f, 0x38, 0x8c, 0x08, 0x4a, 0xa3,
|
||||
0x0b, 0xd2, 0x96, 0xf1, 0x5e, 0x5c, 0x1b, 0x9a, 0xce, 0x5b, 0x8b,
|
||||
0x54, 0x36, 0x1e, 0xe3, 0x68, 0x4e, 0x91, 0x1c, 0x02, 0x37, 0xcc,
|
||||
0x2a, 0xa5, 0x4b, 0x8d, 0xc4, 0x7c, 0x43, 0x04, 0x97, 0x83, 0xd6,
|
||||
0xda, 0x18, 0x2f, 0xf5, 0x1e, 0xb2, 0xaa, 0x22, 0x68, 0x28, 0x92,
|
||||
0x17, 0x39, 0x74, 0x6b, 0xfb, 0xbd, 0xd4, 0xa1, 0x6a, 0x8a, 0x82,
|
||||
0xaa, 0x0c, 0x1e, 0xbb, 0x79, 0xfc, 0x0d, 0xf5, 0x35, 0xd2, 0x08,
|
||||
0x5d, 0x1b, 0x12, 0x98, 0x1d, 0x7b, 0x65, 0x61, 0x53, 0x19, 0x68,
|
||||
0xcf, 0x75, 0x9f, 0x85, 0x3f, 0xa9, 0xb5, 0x43, 0xf9, 0xd1, 0x1a,
|
||||
0xab, 0x89, 0xc9, 0x79, 0x6f, 0x78, 0x6e, 0xac, 0x2f, 0xe3, 0x17,
|
||||
0x29, 0xef, 0x0f, 0xde, 0x36, 0xeb, 0x43, 0xec, 0x00, 0x00, 0x00,
|
||||
0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
|
||||
};
|
||||
|
||||
const int default_right_icon_len = 526;
|
||||
|
||||
|
||||
/*
|
||||
* This table was generated by the command:
|
||||
*
|
||||
* bin2c -n default_up_icon up.png
|
||||
*/
|
||||
|
||||
const unsigned char default_up_icon[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
|
||||
0x00, 0x1e, 0x08, 0x03, 0x00, 0x00, 0x00, 0x0c, 0xee, 0x5e, 0x90,
|
||||
0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1,
|
||||
0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x2d, 0x50, 0x4c,
|
||||
0x54, 0x45, 0xeb, 0xed, 0xee, 0xdd, 0xe1, 0xe3, 0xcf, 0xd4, 0xd7,
|
||||
0xc9, 0xcf, 0xd2, 0xc2, 0xc9, 0xcd, 0xb4, 0xbc, 0xc1, 0xad, 0xb6,
|
||||
0xbb, 0x98, 0xa3, 0xaa, 0x92, 0x9e, 0xa5, 0x7d, 0x8b, 0x94, 0x70,
|
||||
0x7f, 0x88, 0x65, 0x72, 0x7a, 0x5f, 0x6b, 0x73, 0x54, 0x5f, 0x66,
|
||||
0x4a, 0x53, 0x59, 0xac, 0xfc, 0xc3, 0x4d, 0x00, 0x00, 0x01, 0xa3,
|
||||
0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0x53, 0x59, 0x96, 0xc3,
|
||||
0x30, 0x08, 0x8b, 0x59, 0xbd, 0x90, 0xdc, 0xff, 0xb8, 0x23, 0xe1,
|
||||
0x7e, 0x0e, 0xaf, 0x75, 0x5a, 0x8b, 0x45, 0x02, 0xf2, 0x3c, 0xff,
|
||||
0x98, 0xc8, 0xef, 0x47, 0xfd, 0x87, 0x3e, 0x63, 0xdc, 0x67, 0x10,
|
||||
0x16, 0x53, 0x33, 0x15, 0x19, 0xfc, 0xa8, 0x8c, 0x21, 0x9e, 0x99,
|
||||
0xe1, 0x22, 0xeb, 0x00, 0x06, 0xe4, 0x19, 0x86, 0x6b, 0x98, 0xeb,
|
||||
0x78, 0x86, 0x7a, 0x84, 0x9b, 0xe8, 0xde, 0x80, 0x55, 0x34, 0x66,
|
||||
0x20, 0x4c, 0xdc, 0x1d, 0x41, 0xf0, 0x33, 0x55, 0x35, 0xf7, 0xb5,
|
||||
0x00, 0xbb, 0x9b, 0x7f, 0xdf, 0xf7, 0xbe, 0x6f, 0x1f, 0x3f, 0x13,
|
||||
0x73, 0x5b, 0x8c, 0xce, 0xf4, 0x86, 0xeb, 0x7d, 0xeb, 0x9c, 0x2a,
|
||||
0x1c, 0x78, 0xa0, 0xd0, 0x98, 0x84, 0x03, 0x46, 0xf8, 0xb4, 0x11,
|
||||
0xdc, 0xfb, 0x1c, 0xd3, 0x31, 0x62, 0xb2, 0x36, 0x8a, 0x5b, 0x04,
|
||||
0xf8, 0xa3, 0xb2, 0x3b, 0x1e, 0x26, 0xa2, 0xe0, 0x20, 0xc9, 0xda,
|
||||
0xd6, 0x8c, 0x89, 0xc0, 0x20, 0xb1, 0x71, 0xc0, 0x62, 0x93, 0xd1,
|
||||
0x66, 0x70, 0xb0, 0x0b, 0xaf, 0xa9, 0x74, 0x71, 0xf8, 0x10, 0xce,
|
||||
0x1f, 0x0c, 0xa5, 0x06, 0xc0, 0xab, 0x80, 0x41, 0x68, 0xe0, 0x52,
|
||||
0xa3, 0x48, 0x8d, 0xbe, 0xe8, 0x83, 0x22, 0xc3, 0x79, 0x6b, 0xb1,
|
||||
0x81, 0x2c, 0x05, 0xf7, 0xaa, 0xab, 0x1b, 0x2d, 0x00, 0xec, 0x1b,
|
||||
0xea, 0xaa, 0x39, 0xe2, 0x3f, 0x52, 0x9e, 0x6a, 0x61, 0xde, 0x74,
|
||||
0xd4, 0x5b, 0xdd, 0x62, 0x2a, 0x04, 0x20, 0xfd, 0x85, 0x1d, 0xca,
|
||||
0x40, 0xc4, 0xd7, 0xf7, 0x15, 0x34, 0xa3, 0x4b, 0x24, 0xd3, 0x4c,
|
||||
0x7a, 0xba, 0x72, 0xa5, 0x31, 0x78, 0xc3, 0xbc, 0xd3, 0x83, 0x5b,
|
||||
0x8f, 0x04, 0x53, 0xec, 0x60, 0x56, 0xde, 0x7b, 0xad, 0x3d, 0xc9,
|
||||
0x05, 0xfa, 0xa5, 0x75, 0xa3, 0x96, 0x33, 0xd7, 0xc7, 0x9e, 0xaf,
|
||||
0x35, 0xd7, 0xbe, 0xc4, 0xcc, 0x3a, 0x3a, 0xe6, 0x44, 0x39, 0x87,
|
||||
0x28, 0x54, 0x5e, 0xc4, 0x17, 0x96, 0x81, 0x62, 0xba, 0x76, 0x24,
|
||||
0x60, 0x4b, 0x8e, 0x6b, 0x13, 0x9b, 0x73, 0xcf, 0xe8, 0xee, 0xf7,
|
||||
0x40, 0x15, 0xbb, 0x63, 0x52, 0x28, 0x7c, 0x43, 0x67, 0x22, 0x3d,
|
||||
0xa6, 0xe8, 0x12, 0xd1, 0xbb, 0x16, 0x21, 0xf3, 0x25, 0x3c, 0xe9,
|
||||
0x00, 0x43, 0x76, 0xb4, 0x71, 0x04, 0x7b, 0xae, 0xcc, 0xf4, 0x36,
|
||||
0xbc, 0x20, 0xab, 0xe1, 0x0d, 0x18, 0xeb, 0xd0, 0xba, 0x23, 0xcd,
|
||||
0x79, 0x09, 0x82, 0x7d, 0x70, 0x3f, 0x8c, 0x5d, 0xde, 0x0d, 0x73,
|
||||
0xfc, 0xb8, 0x4b, 0x8c, 0xb8, 0x0f, 0xca, 0xea, 0xbd, 0x3c, 0xa4,
|
||||
0xc6, 0x8e, 0xb2, 0xe9, 0xb8, 0x94, 0x0e, 0x4b, 0x94, 0x1d, 0x03,
|
||||
0x8c, 0xea, 0xfc, 0x9a, 0xaa, 0xfc, 0x2a, 0x3b, 0x6d, 0xdc, 0xf1,
|
||||
0x7e, 0x21, 0x6e, 0x74, 0xec, 0x95, 0x13, 0x7c, 0x49, 0x36, 0xc1,
|
||||
0x1c, 0xea, 0xf1, 0x27, 0xc9, 0x72, 0xe5, 0x83, 0xc5, 0xad, 0x16,
|
||||
0x43, 0x98, 0x78, 0xd5, 0xc6, 0x2b, 0x14, 0xf3, 0x1c, 0x5c, 0xfd,
|
||||
0x01, 0x56, 0x35, 0x13, 0x9e, 0xbd, 0x4e, 0x62, 0x4e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
|
||||
};
|
||||
|
||||
const int default_up_icon_len = 549;
|
||||
|
||||
|
||||
/*
|
||||
* This table was generated by the command:
|
||||
*
|
||||
* bin2c -n default_movie_icon movie.png
|
||||
*/
|
||||
|
||||
const unsigned char default_movie_icon[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
|
||||
0x00, 0x16, 0x04, 0x03, 0x00, 0x00, 0x00, 0x32, 0x6f, 0xa1, 0x35,
|
||||
0x00, 0x00, 0x00, 0x15, 0x50, 0x4c, 0x54, 0x45, 0xcc, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x99, 0x99, 0x99, 0x66, 0x66,
|
||||
0x66, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x89, 0x10, 0x3a, 0x6d,
|
||||
0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x06, 0x61, 0x66,
|
||||
0xb8, 0x7d, 0x00, 0x00, 0x00, 0x39, 0x49, 0x44, 0x41, 0x54, 0x78,
|
||||
0xda, 0x63, 0x48, 0x83, 0x82, 0x04, 0x06, 0x86, 0x24, 0x35, 0x30,
|
||||
0x4b, 0x29, 0x15, 0xc4, 0x74, 0x01, 0x02, 0x31, 0x10, 0x33, 0x2d,
|
||||
0xcd, 0xd9, 0xd8, 0xd8, 0x58, 0x2c, 0x0d, 0x2c, 0x0a, 0x66, 0x2a,
|
||||
0xa1, 0x32, 0x89, 0x50, 0x20, 0x08, 0x04, 0x50, 0x05, 0xf4, 0xb5,
|
||||
0x02, 0xce, 0x64, 0x0d, 0x85, 0x02, 0x06, 0x00, 0x66, 0x25, 0x34,
|
||||
0xea, 0x21, 0xc4, 0xeb, 0x5e, 0x00, 0x00, 0x00, 0x56, 0x74, 0x45,
|
||||
0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x54,
|
||||
0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x20, 0x69, 0x73, 0x20,
|
||||
0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c,
|
||||
0x69, 0x63, 0x20, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x20,
|
||||
0x4b, 0x65, 0x76, 0x69, 0x6e, 0x20, 0x48, 0x75, 0x67, 0x68, 0x65,
|
||||
0x73, 0x2c, 0x20, 0x6b, 0x65, 0x76, 0x69, 0x6e, 0x68, 0x40, 0x65,
|
||||
0x69, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x53, 0x65, 0x70,
|
||||
0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x31, 0x39, 0x39, 0x35,
|
||||
0x4c, 0xe8, 0xf4, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e,
|
||||
0x44, 0xae, 0x42, 0x60, 0x82
|
||||
};
|
||||
|
||||
const int default_movie_icon_len = 258;
|
||||
|
||||
|
||||
/*
|
||||
* This table was generated by the command:
|
||||
*
|
||||
* bin2c -n default_sound_icon sound.png
|
||||
*/
|
||||
|
||||
const unsigned char default_sound_icon[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
|
||||
0x00, 0x16, 0x04, 0x03, 0x00, 0x00, 0x00, 0x32, 0x6f, 0xa1, 0x35,
|
||||
0x00, 0x00, 0x00, 0x18, 0x50, 0x4c, 0x54, 0x45, 0xcc, 0xff, 0xff,
|
||||
0xff, 0x33, 0x33, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x99, 0x99,
|
||||
0x99, 0x66, 0x00, 0x00, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0xfd,
|
||||
0xef, 0xcf, 0xe1, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44,
|
||||
0x07, 0x16, 0x61, 0x88, 0xeb, 0x00, 0x00, 0x00, 0x6a, 0x49, 0x44,
|
||||
0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0xc0, 0x0d, 0x12, 0x18, 0x18,
|
||||
0x05, 0x20, 0x2c, 0xf6, 0x02, 0x41, 0x06, 0x41, 0x08, 0xb3, 0xa4,
|
||||
0x80, 0x51, 0x00, 0x22, 0xcc, 0xee, 0x54, 0xc0, 0x20, 0x08, 0x61,
|
||||
0x96, 0x28, 0x15, 0x08, 0x30, 0x02, 0x55, 0xb0, 0x97, 0x97, 0x3b,
|
||||
0x29, 0x15, 0x00, 0x05, 0x03, 0x19, 0x4a, 0x5c, 0x5c, 0x94, 0x80,
|
||||
0x4c, 0x56, 0x10, 0x53, 0x09, 0x08, 0x0a, 0x02, 0x89, 0x63, 0xa6,
|
||||
0xa4, 0x24, 0x41, 0xb5, 0x01, 0x0d, 0x33, 0x83, 0x1a, 0xc6, 0x90,
|
||||
0x96, 0x56, 0x9c, 0x04, 0xb1, 0x02, 0x08, 0xd2, 0xcd, 0xe0, 0x16,
|
||||
0xb3, 0x15, 0x83, 0x9c, 0x03, 0x71, 0x59, 0x3a, 0xc2, 0x91, 0x6c,
|
||||
0x08, 0xa7, 0x63, 0x00, 0x00, 0xac, 0x1b, 0x1b, 0xa7, 0x07, 0x45,
|
||||
0x3c, 0x76, 0x00, 0x00, 0x00, 0x56, 0x74, 0x45, 0x58, 0x74, 0x43,
|
||||
0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x54, 0x68, 0x69, 0x73,
|
||||
0x20, 0x61, 0x72, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20,
|
||||
0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
|
||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4b, 0x65, 0x76,
|
||||
0x69, 0x6e, 0x20, 0x48, 0x75, 0x67, 0x68, 0x65, 0x73, 0x2c, 0x20,
|
||||
0x6b, 0x65, 0x76, 0x69, 0x6e, 0x68, 0x40, 0x65, 0x69, 0x74, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d,
|
||||
0x62, 0x65, 0x72, 0x20, 0x31, 0x39, 0x39, 0x35, 0x4c, 0xe8, 0xf4,
|
||||
0xc4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
|
||||
0x60, 0x82
|
||||
};
|
||||
|
||||
const int default_sound_icon_len = 310;
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Filename: default_index_icons.h
|
||||
// Created by: drose (04Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef DEFAULT_INDEX_ICONS_H
|
||||
#define DEFAULT_INDEX_ICONS_H
|
||||
|
||||
extern const char *default_left_icon_filename;
|
||||
extern const char *default_right_icon_filename;
|
||||
extern const char *default_up_icon_filename;
|
||||
extern const char *default_movie_icon_filename;
|
||||
extern const char *default_sound_icon_filename;
|
||||
|
||||
extern const unsigned char default_left_icon[];
|
||||
extern const int default_left_icon_len;
|
||||
extern const unsigned char default_right_icon[];
|
||||
extern const int default_right_icon_len;
|
||||
extern const unsigned char default_up_icon[];
|
||||
extern const int default_up_icon_len;
|
||||
extern const unsigned char default_movie_icon[];
|
||||
extern const int default_movie_icon_len;
|
||||
extern const unsigned char default_sound_icon[];
|
||||
extern const int default_sound_icon_len;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,264 +0,0 @@
|
|||
// Filename: fontSamples.cxx
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "fontSamples.h"
|
||||
#include "pnmTextMaker.h"
|
||||
#include "default_font.h"
|
||||
#include "pnmImage.h"
|
||||
#include "pnotify.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WIN32_VC
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FontSamples::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
FontSamples::
|
||||
FontSamples() {
|
||||
clear_runlines();
|
||||
add_runline("[opts] fontname [fontname ...]");
|
||||
|
||||
set_program_description
|
||||
("Generates one or more image files with one line of text from "
|
||||
"each of several given font files, as a font sample sheet.");
|
||||
|
||||
add_option
|
||||
("t", "text", 0,
|
||||
"Specifies the sample text to render using each font.",
|
||||
&FontSamples::dispatch_string, NULL, &_sample_text);
|
||||
|
||||
add_option
|
||||
("sh", "height", 0,
|
||||
"Specifies the pixel height of each sample.",
|
||||
&FontSamples::dispatch_int, NULL, &_sample_height);
|
||||
|
||||
add_option
|
||||
("nf", "filename", 0,
|
||||
"Specifies the filename of the font to be used to write each font's "
|
||||
"name.",
|
||||
&FontSamples::dispatch_filename, NULL, &_name_font_filename);
|
||||
|
||||
add_option
|
||||
("nh", "height", 0,
|
||||
"Specifies the pixel height of each font's name.",
|
||||
&FontSamples::dispatch_int, NULL, &_name_height);
|
||||
|
||||
add_option
|
||||
("fontaa", "factor", 0,
|
||||
"Specifies a scale factor to apply to the fonts "
|
||||
"for the purpose of antialiasing the fonts a "
|
||||
"little better than FreeType can do by itself. The letters are "
|
||||
"generated large and then scaled to their proper size. Normally this "
|
||||
"should be a number in the range 3 to 4 for best effect.",
|
||||
&FontSamples::dispatch_double, NULL, &_font_aa_factor);
|
||||
|
||||
add_option
|
||||
("space", "y", 0,
|
||||
"Specifies the vertical space in pixels between font samples.",
|
||||
&FontSamples::dispatch_int, NULL, &_vert_space);
|
||||
|
||||
add_option
|
||||
("image", "x, y", 0,
|
||||
"Specifies the width and height in pixels of the resulting image(s).",
|
||||
&FontSamples::dispatch_int_pair, NULL, &_image_width);
|
||||
|
||||
add_option
|
||||
("o", "filename", 50,
|
||||
"Specify the filename(s) to which the resulting image file will "
|
||||
"be written. This should contain the string '%d' which will be "
|
||||
"filled in with the index number of the particular frame.",
|
||||
&FontSamples::dispatch_string, NULL, &_output_filename);
|
||||
|
||||
_sample_text = "The quick brown fox jumped over the lazy dog's back.";
|
||||
_sample_height = 14;
|
||||
_name_height = 10;
|
||||
_font_aa_factor = 4.0;
|
||||
_vert_space = 10;
|
||||
_image_width = 600;
|
||||
_image_height = 600;
|
||||
_output_filename = "samples-%d.jpg";
|
||||
_name_text_maker = (PNMTextMaker *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FontSamples::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
FontSamples::
|
||||
~FontSamples() {
|
||||
if (_name_text_maker != (PNMTextMaker *)NULL) {
|
||||
delete _name_text_maker;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FontSamples::handle_args
|
||||
// Access: Protected, Virtual
|
||||
// Description: Does something with the additional arguments on the
|
||||
// command line (after all the -options have been
|
||||
// parsed). Returns true if the arguments are good,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool FontSamples::
|
||||
handle_args(ProgramBase::Args &args) {
|
||||
if (args.empty()) {
|
||||
nout << "You must specify the font filenames on the command line.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
Args::const_iterator ai;
|
||||
for (ai = args.begin(); ai != args.end(); ++ai) {
|
||||
Filename filename = Filename::from_os_specific(*ai);
|
||||
filename.standardize();
|
||||
if (filename.exists()) {
|
||||
_font_filenames.push_back(filename);
|
||||
|
||||
} else {
|
||||
nout << filename << " does not exist.\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FontSamples::post_command_line
|
||||
// Access: Protected, Virtual
|
||||
// Description: This is called after the command line has been
|
||||
// completely processed, and it gives the program a
|
||||
// chance to do some last-minute processing and
|
||||
// validation of the options and arguments. It should
|
||||
// return true if everything is fine, false if there is
|
||||
// an error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool FontSamples::
|
||||
post_command_line() {
|
||||
if (_font_filenames.empty()) {
|
||||
nout << "No font filenames.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_name_height != 0) {
|
||||
if (!_name_font_filename.empty()) {
|
||||
_name_text_maker = new PNMTextMaker(_name_font_filename, 0);
|
||||
if (!_name_text_maker->is_valid()) {
|
||||
delete _name_text_maker;
|
||||
_name_text_maker = (PNMTextMaker *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (_name_text_maker == (PNMTextMaker *)NULL) {
|
||||
_name_text_maker = new PNMTextMaker((const char *)default_font,
|
||||
default_font_size, 0);
|
||||
if (!_name_text_maker->is_valid()) {
|
||||
nout << "Unable to open default font.\n";
|
||||
delete _name_text_maker;
|
||||
_name_text_maker = (PNMTextMaker *)NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_name_text_maker != (PNMTextMaker *)NULL) {
|
||||
_name_text_maker->set_scale_factor(_font_aa_factor);
|
||||
_name_text_maker->set_pixel_size(_name_height);
|
||||
} else {
|
||||
_name_height = 0;
|
||||
}
|
||||
|
||||
return ProgramBase::post_command_line();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FontSamples::run
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FontSamples::
|
||||
run() {
|
||||
int output_index = 1;
|
||||
PNMImage output_image(_image_width, _image_height, 1);
|
||||
static const int output_filename_size = 1024;
|
||||
char output_filename[output_filename_size];
|
||||
|
||||
bool all_ok = true;
|
||||
|
||||
output_image.fill(1, 1, 1);
|
||||
int y = _vert_space;
|
||||
|
||||
int vert_per_font =
|
||||
_sample_height + _name_height + _vert_space;
|
||||
|
||||
Filenames::iterator fi;
|
||||
for (fi = _font_filenames.begin(); fi != _font_filenames.end(); ++fi) {
|
||||
if (y > _image_height - vert_per_font) {
|
||||
// Write out the current image.
|
||||
snprintf(output_filename, output_filename_size,
|
||||
_output_filename.c_str(), output_index);
|
||||
nout << "Writing " << output_filename << "\n";
|
||||
if (!output_image.write(output_filename)) {
|
||||
nout << "Unable to write to " << output_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
output_index++;
|
||||
output_image.fill(1, 1, 1);
|
||||
y = _vert_space;
|
||||
}
|
||||
const Filename &filename = (*fi);
|
||||
PNMTextMaker *text_maker = new PNMTextMaker(filename, 0);
|
||||
if (!text_maker->is_valid()) {
|
||||
all_ok = false;
|
||||
} else {
|
||||
text_maker->set_scale_factor(_font_aa_factor);
|
||||
text_maker->set_pixel_size(_sample_height);
|
||||
text_maker->generate_into(_sample_text, output_image,
|
||||
16, y + _sample_height);
|
||||
if (_name_text_maker != (PNMTextMaker *)NULL) {
|
||||
string desc = filename.get_basename() + ": " + text_maker->get_name();
|
||||
_name_text_maker->generate_into(desc, output_image,
|
||||
16, y + _sample_height + _name_height);
|
||||
}
|
||||
}
|
||||
|
||||
y += vert_per_font;
|
||||
delete text_maker;
|
||||
}
|
||||
|
||||
snprintf(output_filename, output_filename_size,
|
||||
_output_filename.c_str(), output_index);
|
||||
nout << "Writing " << output_filename << "\n";
|
||||
if (!output_image.write(output_filename)) {
|
||||
nout << "Unable to write to " << output_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!all_ok) {
|
||||
nout << "Problem loading fonts.\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
FontSamples prog;
|
||||
prog.parse_command_line(argc, argv);
|
||||
prog.run();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
// Filename: indexify.h
|
||||
// Created by: drose (07Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef FONTSAMPLES_H
|
||||
#define FONTSAMPLES_H
|
||||
|
||||
#include "pandatoolbase.h"
|
||||
|
||||
#include "programBase.h"
|
||||
#include "filename.h"
|
||||
#include "pvector.h"
|
||||
|
||||
class PNMTextMaker;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : FontSamples
|
||||
// Description : A program to generate one or more image files showing
|
||||
// samples of various fonts.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class FontSamples : public ProgramBase {
|
||||
public:
|
||||
FontSamples();
|
||||
virtual ~FontSamples();
|
||||
|
||||
protected:
|
||||
virtual bool handle_args(Args &args);
|
||||
virtual bool post_command_line();
|
||||
|
||||
public:
|
||||
void run();
|
||||
|
||||
string _sample_text;
|
||||
int _sample_height;
|
||||
int _name_height;
|
||||
Filename _name_font_filename;
|
||||
double _font_aa_factor;
|
||||
int _vert_space;
|
||||
int _image_width;
|
||||
int _image_height;
|
||||
string _output_filename;
|
||||
|
||||
typedef pvector<Filename> Filenames;
|
||||
Filenames _font_filenames;
|
||||
|
||||
PNMTextMaker *_name_text_maker;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,918 +0,0 @@
|
|||
// Filename: indexImage.cxx
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "indexImage.h"
|
||||
#include "rollDirectory.h"
|
||||
#include "photo.h"
|
||||
#include "pnmTextMaker.h"
|
||||
#include "indexParameters.h"
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
|
||||
#include "string_utils.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
IndexImage::
|
||||
IndexImage(RollDirectory *dir, int index) :
|
||||
_dir(dir),
|
||||
_index(index)
|
||||
{
|
||||
_name = _dir->get_basename() + "_" + format_string(index + 1);
|
||||
_index_x_size = 0;
|
||||
_index_y_size = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
IndexImage::
|
||||
~IndexImage() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::add_photo
|
||||
// Access: Public
|
||||
// Description: Adds the nth photo in the roll to the index image.
|
||||
// Returns true if the photo is added, or false if there
|
||||
// was no more room.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool IndexImage::
|
||||
add_photo(int photo_index) {
|
||||
int count = _photos.size();
|
||||
if (count >= max_thumbs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int yi = count / thumb_count_x;
|
||||
int xi = count - (yi * thumb_count_x);
|
||||
|
||||
int x = thumb_x_space + xi * (thumb_width + thumb_x_space);
|
||||
int y = thumb_y_space + yi * (thumb_height + thumb_caption_height + thumb_y_space);
|
||||
|
||||
PhotoInfo pinfo;
|
||||
pinfo._photo_index = photo_index;
|
||||
pinfo._x_place = x;
|
||||
pinfo._y_place = y;
|
||||
_photos.push_back(pinfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::generate_images
|
||||
// Access: Public
|
||||
// Description: Computes the thumbnail image file and writes it to
|
||||
// the indicated directory; generates all reduced images
|
||||
// associated with these photos into the appropriate
|
||||
// subdirectory. Returns true on success, false on
|
||||
// failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool IndexImage::
|
||||
generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
|
||||
int count = _photos.size();
|
||||
int num_rows = (count + thumb_count_x - 1) / thumb_count_x;
|
||||
int actual_index_height = thumb_y_space + num_rows * (thumb_height + thumb_caption_height + thumb_y_space);
|
||||
|
||||
PNMImage index_image;
|
||||
|
||||
Filename thumbnail_dir(archive_dir, "thumbs");
|
||||
Filename output_filename(thumbnail_dir, _name);
|
||||
output_filename.set_extension("jpg");
|
||||
|
||||
Photos::const_iterator pi;
|
||||
|
||||
// First, scan the image files to see if we can avoid regenerating
|
||||
// the index image.
|
||||
bool generate_index_image = true;
|
||||
if (!dummy_mode && !force_regenerate && output_filename.exists()) {
|
||||
// Maybe we don't need to renegerate the index.
|
||||
generate_index_image = false;
|
||||
|
||||
const Filename &newest_contributing_filename =
|
||||
_dir->get_newest_contributing_filename();
|
||||
if (!newest_contributing_filename.empty()) {
|
||||
generate_index_image =
|
||||
(output_filename.compare_timestamps(newest_contributing_filename) < 0);
|
||||
}
|
||||
|
||||
for (pi = _photos.begin();
|
||||
pi != _photos.end() && !generate_index_image;
|
||||
++pi) {
|
||||
const PhotoInfo &pinfo = (*pi);
|
||||
Photo *photo = _dir->get_photo(pinfo._photo_index);
|
||||
Filename photo_filename(_dir->get_dir(), photo->get_basename());
|
||||
|
||||
// If any of the source photos are newer than the index image,
|
||||
// we must regenerate it.
|
||||
generate_index_image =
|
||||
(output_filename.compare_timestamps(photo_filename) < 0);
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't need to regenerate the index, we do need to at least
|
||||
// scan the header.
|
||||
if (!generate_index_image) {
|
||||
if (index_image.read_header(output_filename)) {
|
||||
if (index_image.get_x_size() != actual_index_width ||
|
||||
index_image.get_y_size() != actual_index_height) {
|
||||
// If the index exists but is the wrong size, we'd better
|
||||
// regenerate it.
|
||||
generate_index_image = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// If we couldn't even read the header, we'd better regenerate it
|
||||
// after all.
|
||||
nout << "Couldn't read " << output_filename << "; regenerating.\n";
|
||||
generate_index_image = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (generate_index_image) {
|
||||
index_image.clear(actual_index_width, actual_index_height);
|
||||
index_image.fill(1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
// Now go back through and read whichever images are necessary, or
|
||||
// just read the headers if we can get away with it.
|
||||
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
|
||||
const PhotoInfo &pinfo = (*pi);
|
||||
Photo *photo = _dir->get_photo(pinfo._photo_index);
|
||||
PNMImage reduced_image;
|
||||
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 {
|
||||
thumbnail_image.quick_filter_from(reduced_image);
|
||||
}
|
||||
// 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,
|
||||
thumb_width, thumb_height,
|
||||
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);
|
||||
if (photo->_has_movie && get_movie_icon().is_valid()) {
|
||||
const PNMImage &movie_icon_image = get_movie_icon();
|
||||
int icon_x = label_x - width / 2 - movie_icon_image.get_x_size();
|
||||
int icon_y = label_y - movie_icon_image.get_y_size();
|
||||
|
||||
index_image.blend_sub_image(movie_icon_image, icon_x, icon_y);
|
||||
} else if (photo->_has_sound && get_sound_icon().is_valid()) {
|
||||
const PNMImage &sound_icon_image = get_sound_icon();
|
||||
int icon_x = label_x - width / 2 - sound_icon_image.get_x_size();
|
||||
int icon_y = label_y - sound_icon_image.get_y_size();
|
||||
|
||||
index_image.blend_sub_image(sound_icon_image, icon_x, icon_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (generate_index_image) {
|
||||
nout << "Writing " << output_filename << "\n";
|
||||
output_filename.make_dir();
|
||||
if (!index_image.write(output_filename)) {
|
||||
nout << "Unable to write.\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_index_x_size = index_image.get_x_size();
|
||||
_index_y_size = index_image.get_y_size();
|
||||
_index_basename = output_filename.get_basename();
|
||||
|
||||
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.
|
||||
photo_filename.set_binary();
|
||||
if (!copy_file(photo_filename, reduced_dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} 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.
|
||||
|
||||
if (!force_reduced) {
|
||||
// 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
|
||||
// Description: Generates all HTML files associated with reduced
|
||||
// images into the appropriate subdirectory, and
|
||||
// generates root-level HTML code to access the
|
||||
// thumbnails on the index image into the indicated
|
||||
// stream.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool IndexImage::
|
||||
generate_html(ostream &root_html, const Filename &archive_dir,
|
||||
const Filename &roll_dir_root) {
|
||||
root_html
|
||||
<< "<a name=\"" << _name << "\">\n"
|
||||
<< "<img src=\"../thumbs/" << _index_basename
|
||||
<< "\" width=" << _index_x_size << " height=" << _index_y_size
|
||||
<< " ismap usemap=\"#" << _name << "\">\n"
|
||||
<< "<map name=\"" << _name << "\"><br>\n";
|
||||
|
||||
Filename html_dir(archive_dir, "html");
|
||||
|
||||
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);
|
||||
Filename html_relname(_dir->get_basename(), photo->get_basename());
|
||||
html_relname.set_extension("htm");
|
||||
|
||||
Filename html_filename(html_dir, html_relname);
|
||||
html_filename.make_dir();
|
||||
html_filename.set_text();
|
||||
ofstream reduced_html;
|
||||
if (!html_filename.open_write(reduced_html)) {
|
||||
nout << "Unable to write to " << html_filename << "\n";
|
||||
return false;
|
||||
}
|
||||
if (!generate_reduced_html(reduced_html, photo, photo_index,
|
||||
pi - _photos.begin(), roll_dir_root)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
root_html
|
||||
<< " <area shape=\"RECT\" href=\"" << html_relname
|
||||
<< "\" coords=\""
|
||||
<< pinfo._x_place << "," << pinfo._y_place << ","
|
||||
<< pinfo._x_place + thumb_width << ","
|
||||
<< pinfo._y_place + thumb_height + thumb_caption_height
|
||||
<< "\">\n";
|
||||
}
|
||||
|
||||
root_html
|
||||
<< "</map>\n";
|
||||
|
||||
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(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (photo->_has_sound) {
|
||||
// Also copy the sound clip to the reduced directory.
|
||||
Filename sound_filename(_dir->get_dir(), photo->get_sound());
|
||||
if (sound_filename.exists()) {
|
||||
sound_filename.set_binary();
|
||||
Filename reduced_dir(archive_dir, "reduced/" + _dir->get_basename());
|
||||
if (!copy_file(sound_filename, reduced_dir)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::output
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void IndexImage::
|
||||
output(ostream &out) const {
|
||||
out << _name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::write
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void IndexImage::
|
||||
write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level)
|
||||
<< _name << "\n";
|
||||
Photos::const_iterator pi;
|
||||
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
|
||||
const PhotoInfo &pinfo = (*pi);
|
||||
indent(out, indent_level + 2)
|
||||
<< *_dir->get_photo(pinfo._photo_index) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::generate_reduced_html
|
||||
// Access: Public
|
||||
// Description: Generates HTML code for rendering the indicated
|
||||
// reduced-image photo into the given ostream.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool IndexImage::
|
||||
generate_reduced_html(ostream &html, Photo *photo, int photo_index, int pi,
|
||||
const Filename &roll_dir_root) {
|
||||
Filename full_dir;
|
||||
if (roll_dir_root.empty()) {
|
||||
full_dir = Filename("../..", _dir->get_dir());
|
||||
} else {
|
||||
compose_href("../..", roll_dir_root, _dir->get_basename());
|
||||
}
|
||||
Filename full(full_dir, photo->get_basename());
|
||||
Filename movie(full_dir, photo->get_movie());
|
||||
Filename sound(full_dir, photo->get_sound());
|
||||
|
||||
Filename reduced_dir("../../reduced", _dir->get_basename());
|
||||
Filename reduced(reduced_dir, photo->get_basename());
|
||||
if (!photo->_has_reduced) {
|
||||
reduced_dir = full_dir;
|
||||
reduced = full;
|
||||
}
|
||||
|
||||
string up_href = "../" + _dir->get_basename() + ".htm#" + _name;
|
||||
|
||||
Filename prev_photo_filename;
|
||||
Filename next_photo_filename;
|
||||
|
||||
if (pi != 0) {
|
||||
// If this is not the first photo on the index, "back" will take
|
||||
// us to the previous photo on the same index.
|
||||
Photo *prev_photo = _dir->get_photo(_photos[pi - 1]._photo_index);
|
||||
prev_photo_filename = Filename(prev_photo->get_basename());
|
||||
prev_photo_filename.set_extension("htm");
|
||||
|
||||
} else {
|
||||
// If this is the first photo on the index, "back" will take us to
|
||||
// the last photo on the previous index. Or even to the last
|
||||
// photo on the previous roll.
|
||||
RollDirectory *roll_dir = _dir;
|
||||
int index = _index - 1;
|
||||
while (index < 0 && roll_dir->_prev != (RollDirectory *)NULL) {
|
||||
roll_dir = roll_dir->_prev;
|
||||
index = roll_dir->get_num_index_images() - 1;
|
||||
}
|
||||
|
||||
if (index >= 0) {
|
||||
IndexImage *prev_index = roll_dir->get_index_image(index);
|
||||
nassertr(!prev_index->_photos.empty(), false);
|
||||
Photo *prev_photo =
|
||||
roll_dir->get_photo(prev_index->_photos.back()._photo_index);
|
||||
Filename other_dir("..", roll_dir->get_basename());
|
||||
prev_photo_filename = Filename(other_dir, prev_photo->get_basename());
|
||||
prev_photo_filename.set_extension("htm");
|
||||
}
|
||||
}
|
||||
|
||||
if (pi + 1 < (int)_photos.size()) {
|
||||
// If this is not the last photo, "next" will take us to the next
|
||||
// photo on the same index.
|
||||
Photo *next_photo = _dir->get_photo(_photos[pi + 1]._photo_index);
|
||||
next_photo_filename = Filename(next_photo->get_basename());
|
||||
next_photo_filename.set_extension("htm");
|
||||
|
||||
} else {
|
||||
// If this is the last photo on the index, "next" will take us to
|
||||
// the first photo on the next index. Or even to the first photo
|
||||
// on the next roll.
|
||||
|
||||
RollDirectory *roll_dir = _dir;
|
||||
int index = _index + 1;
|
||||
while (index >= roll_dir->get_num_index_images() &&
|
||||
roll_dir->_next != (RollDirectory *)NULL) {
|
||||
roll_dir = roll_dir->_next;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
if (index < roll_dir->get_num_index_images()) {
|
||||
IndexImage *next_index = roll_dir->get_index_image(index);
|
||||
nassertr(!next_index->_photos.empty(), false);
|
||||
Photo *next_photo =
|
||||
roll_dir->get_photo(next_index->_photos.front()._photo_index);
|
||||
Filename other_dir("..", roll_dir->get_basename());
|
||||
next_photo_filename = Filename(other_dir, next_photo->get_basename());
|
||||
next_photo_filename.set_extension("htm");
|
||||
}
|
||||
}
|
||||
|
||||
html
|
||||
<< "<html>\n"
|
||||
<< "<head>\n"
|
||||
<< "<title>" << photo->get_name() << " (" << photo_index + 1 << " of "
|
||||
<< _dir->get_num_photos() << " on " << _dir->get_basename()
|
||||
<< ")</title>\n"
|
||||
<< "</head>\n"
|
||||
<< "<body>\n"
|
||||
<< "<h1>" << photo->get_name() << " (" << photo_index + 1 << " of "
|
||||
<< _dir->get_num_photos() << ")</h1>";
|
||||
|
||||
generate_nav_buttons(html, prev_photo_filename, next_photo_filename,
|
||||
up_href);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
html
|
||||
<< "<p><a href=\"" << reduced << "\">"
|
||||
<< "<img src=\"" << reduced << "\" width=" << photo->_reduced_x_size
|
||||
<< " height=" << photo->_reduced_y_size << " alt=\"" << photo->get_name()
|
||||
<< "\"></a></p>\n";
|
||||
|
||||
if (!omit_full_links && photo->_has_reduced) {
|
||||
html
|
||||
<< "<p><a href=\"" << full << "\">View full size image ("
|
||||
<< photo->_full_x_size << " x " << photo->_full_y_size << ")</a></p>\n";
|
||||
}
|
||||
|
||||
if (photo->_has_movie) {
|
||||
html << "<p>";
|
||||
if (!movie_icon.empty()) {
|
||||
// Show the movie icon if we got one.
|
||||
Filename movie_icon_href = compose_href("../..", movie_icon);
|
||||
html << "<img src=\"" << movie_icon_href << "\" alt=\"\">";
|
||||
}
|
||||
|
||||
// Determine the size of the file.
|
||||
streampos size = 0;
|
||||
ifstream stream;
|
||||
Filename movie_filename(_dir->get_dir(), photo->get_movie());
|
||||
movie_filename.set_binary();
|
||||
if (movie_filename.open_read(stream)) {
|
||||
// Seek to the end and get the stream position there.
|
||||
stream.seekg(0, ios::end);
|
||||
size = stream.tellg();
|
||||
}
|
||||
|
||||
static const streampos MB = 1024 * 1024;
|
||||
static const streampos GB = 1024 * 1024 * 1024;
|
||||
string size_units;
|
||||
double size_float = size;
|
||||
|
||||
if (size > GB) {
|
||||
size_units = "GB";
|
||||
size_float = (double)size / (double)GB;
|
||||
} else if (size > MB) {
|
||||
size_units = "MB";
|
||||
size_float = (double)size / (double)MB;
|
||||
}
|
||||
|
||||
if (size_units.empty()) {
|
||||
html
|
||||
<< "<a href=\"" << movie << "\">Play movie</a></p>\n";
|
||||
} else {
|
||||
char buffer[128];
|
||||
sprintf(buffer, "%.1f", size_float);
|
||||
html
|
||||
<< "<a href=\"" << movie << "\">Play movie ("
|
||||
<< buffer << " " << size_units << ")</a></p>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (photo->_has_sound) {
|
||||
html << "<p>";
|
||||
if (!sound_icon.empty()) {
|
||||
// Show the sound icon if we got one.
|
||||
Filename sound_icon_href = compose_href("../..", sound_icon);
|
||||
html << "<img src=\"" << sound_icon_href << "\" alt=\"\">";
|
||||
}
|
||||
|
||||
// Determine the size of the file.
|
||||
streampos size = 0;
|
||||
ifstream stream;
|
||||
Filename sound_filename(_dir->get_dir(), photo->get_sound());
|
||||
sound_filename.set_binary();
|
||||
if (sound_filename.open_read(stream)) {
|
||||
// Seek to the end and get the stream position there.
|
||||
stream.seekg(0, ios::end);
|
||||
size = stream.tellg();
|
||||
}
|
||||
|
||||
static const streampos MB = 1024 * 1024;
|
||||
static const streampos GB = 1024 * 1024 * 1024;
|
||||
string size_units;
|
||||
double size_float = size;
|
||||
|
||||
if (size > GB) {
|
||||
size_units = "GB";
|
||||
size_float = (double)size / (double)GB;
|
||||
} else if (size > MB) {
|
||||
size_units = "MB";
|
||||
size_float = (double)size / (double)MB;
|
||||
}
|
||||
|
||||
if (size_units.empty()) {
|
||||
html
|
||||
<< "<a href=\"" << sound << "\">Play sound clip</a></p>\n";
|
||||
} else {
|
||||
char buffer[128];
|
||||
sprintf(buffer, "%.1f", size_float);
|
||||
html
|
||||
<< "<a href=\"" << sound << "\">Play sound clip ("
|
||||
<< buffer << " " << size_units << ")</a></p>\n";
|
||||
}
|
||||
}
|
||||
|
||||
generate_nav_buttons(html, prev_photo_filename, next_photo_filename,
|
||||
up_href);
|
||||
|
||||
html
|
||||
<< "</body>\n"
|
||||
<< "</html>\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::generate_nav_buttons
|
||||
// Access: Private
|
||||
// Description: Outputs the HTML code to generate the next, prev,
|
||||
// up buttons when viewing each reduced image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void IndexImage::
|
||||
generate_nav_buttons(ostream &html, const Filename &prev_photo_filename,
|
||||
const Filename &next_photo_filename,
|
||||
const string &up_href) {
|
||||
html << "<p>\n";
|
||||
|
||||
bool first_icons = false;
|
||||
if (!prev_icon.empty() && !next_icon.empty()) {
|
||||
first_icons = true;
|
||||
// Use icons to go forward and back.
|
||||
Filename prev_icon_href = compose_href("../..", prev_icon);
|
||||
if (prev_photo_filename.empty()) {
|
||||
html << "<img src=\"" << prev_icon_href << "\" alt=\"No previous photo\">\n";
|
||||
} else {
|
||||
html << "<a href=\"" << prev_photo_filename
|
||||
<< "\"><img src=\"" << prev_icon_href << "\" alt=\"previous\"></a>\n";
|
||||
}
|
||||
|
||||
Filename next_icon_href = compose_href("../..", next_icon);
|
||||
if (next_photo_filename.empty()) {
|
||||
html << "<img src=\"" << next_icon_href << "\" alt=\"No next photo\">\n";
|
||||
} else {
|
||||
html << "<a href=\"" << next_photo_filename
|
||||
<< "\"><img src=\"" << next_icon_href << "\" alt=\"next\"></a>\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
// No prev/next icons; use text to go forward and back.
|
||||
if (prev_photo_filename.empty()) {
|
||||
html << "(This is the first photo.)\n";
|
||||
} else {
|
||||
html << "<a href=\"" << prev_photo_filename
|
||||
<< "\">Back to previous photo</a>\n";
|
||||
}
|
||||
|
||||
if (next_photo_filename.empty()) {
|
||||
html << "<br>(This is the last photo.)\n";
|
||||
} else {
|
||||
html << "<br><a href=\"" << next_photo_filename
|
||||
<< "\">On to next photo</a>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!up_href.empty()) {
|
||||
if (!up_icon.empty()) {
|
||||
// Use an icon to go up.
|
||||
if (!first_icons) {
|
||||
html << "<br>";
|
||||
} else {
|
||||
html << " ";
|
||||
}
|
||||
Filename up_icon_href = compose_href("../..", up_icon);
|
||||
html << "<a href=\"" << up_href
|
||||
<< "\"><img src=\"" << up_icon_href << "\" alt=\"return to index\"></a>\n";
|
||||
} else {
|
||||
// No up icon; use text to go up.
|
||||
html << "<br><a href=\"" << up_href
|
||||
<< "\">Return to index</a>\n";
|
||||
}
|
||||
}
|
||||
html << "</p>\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::compute_reduction
|
||||
// Access: Private, Static
|
||||
// Description: Computes the amount by which the source image must be
|
||||
// scaled to fit within the indicated box, and clears
|
||||
// the dest_image to the computed size.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void IndexImage::
|
||||
compute_reduction(const PNMImageHeader &source_image, PNMImage &dest_image,
|
||||
int x_size, int y_size) {
|
||||
double x_scale = (double)x_size / (double)source_image.get_x_size();
|
||||
double y_scale = (double)y_size / (double)source_image.get_y_size();
|
||||
double scale = min(x_scale, y_scale);
|
||||
|
||||
// Don't ever enlarge an image to fit the rectangle; if the image is
|
||||
// smaller than the rectangle, just leave it small.
|
||||
scale = min(scale, 1.0);
|
||||
|
||||
int new_x_size = (int)(source_image.get_x_size() * scale + 0.5);
|
||||
int new_y_size = (int)(source_image.get_y_size() * scale + 0.5);
|
||||
|
||||
dest_image.clear(new_x_size, new_y_size,
|
||||
source_image.get_num_channels(),
|
||||
source_image.get_maxval());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::draw_box
|
||||
// Access: Private, Static
|
||||
// Description: Called in dummy mode to draw a little box in black
|
||||
// around the border of the empty thumbnail image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void IndexImage::
|
||||
draw_box(PNMImage &image) {
|
||||
// First, fill it in white.
|
||||
image.fill(1, 1, 1);
|
||||
|
||||
if (!draw_frames) {
|
||||
// Now make the border pixel black. We only need to do this if we
|
||||
// aren't drawing frames, since the frames will reveal the shape
|
||||
// of the image too.
|
||||
int x_size = image.get_x_size();
|
||||
int y_size = image.get_y_size();
|
||||
for (int xi = 0; xi < x_size; xi++) {
|
||||
image.set_xel(xi, 0, 0, 0, 0);
|
||||
image.set_xel(xi, y_size - 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
for (int yi = 1; yi < y_size - 1; yi++) {
|
||||
image.set_xel(0, yi, 0, 0, 0);
|
||||
image.set_xel(x_size - 1, yi, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IndexImage::draw_frame
|
||||
// Access: Private, Static
|
||||
// Description: Called in draw_frames mode to draw a slide mount in
|
||||
// gray on the index image before drawing the thumbnail
|
||||
// image in the center.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void IndexImage::
|
||||
draw_frame(PNMImage &image,
|
||||
int frame_left, int frame_top, int frame_width, int frame_height,
|
||||
int hole_left, int hole_top, int hole_width, int hole_height) {
|
||||
// Gray levels.
|
||||
static const RGBColord mid(0.5, 0.5, 0.5);
|
||||
static const RGBColord light(0.7, 0.7, 0.7);
|
||||
static const RGBColord lighter(0.9, 0.9, 0.9);
|
||||
static const RGBColord dark(0.3, 0.3, 0.3);
|
||||
static const RGBColord darker(0.1, 0.1, 0.1);
|
||||
|
||||
// First, fill in the whole rectangle in gray.
|
||||
int xi, yi;
|
||||
for (yi = 0; yi < frame_height; yi++) {
|
||||
for (xi = 0; xi < frame_width; xi++) {
|
||||
image.set_xel(xi + frame_left, yi + frame_top, mid);
|
||||
}
|
||||
}
|
||||
|
||||
// Now draw the bevel.
|
||||
for (xi = 0; xi < frame_outer_bevel; xi++) {
|
||||
for (yi = xi; yi < frame_height - xi; yi++) {
|
||||
// Left edge.
|
||||
image.set_xel(xi + frame_left, yi + frame_top, light);
|
||||
// Right edge.
|
||||
image.set_xel(frame_width - 1 - xi + frame_left, yi + frame_top, dark);
|
||||
}
|
||||
}
|
||||
for (yi = 0; yi < frame_outer_bevel; yi++) {
|
||||
for (xi = yi; xi < frame_width - yi; xi++) {
|
||||
// Top edge.
|
||||
image.set_xel(xi + frame_left, yi + frame_top, lighter);
|
||||
// Bottom edge.
|
||||
image.set_xel(xi + frame_left, frame_height - 1 - yi + frame_top, darker);
|
||||
}
|
||||
}
|
||||
|
||||
// Interior bevel.
|
||||
for (xi = -1; xi >= -frame_inner_bevel; xi--) {
|
||||
for (yi = xi; yi < hole_height - xi; yi++) {
|
||||
// Left edge.
|
||||
image.set_xel(xi + hole_left, yi + hole_top, dark);
|
||||
// Right edge.
|
||||
image.set_xel(hole_width - 1 - xi + hole_left, yi + hole_top, light);
|
||||
}
|
||||
}
|
||||
for (yi = -1; yi >= -frame_inner_bevel; yi--) {
|
||||
for (xi = yi; xi < hole_width - yi; xi++) {
|
||||
// Top edge.
|
||||
image.set_xel(xi + hole_left, yi + hole_top, darker);
|
||||
// Bottom edge.
|
||||
image.set_xel(xi + hole_left, hole_height - 1 - yi + hole_top, lighter);
|
||||
}
|
||||
}
|
||||
|
||||
// We don't have to cut out the hole, since the thumbnail image will
|
||||
// do that when it is placed.
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
// Filename: indexImage.h
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INDEXIMAGE_H
|
||||
#define INDEXIMAGE_H
|
||||
|
||||
#include "pandatoolbase.h"
|
||||
|
||||
#include "filename.h"
|
||||
#include "pvector.h"
|
||||
|
||||
class RollDirectory;
|
||||
class Photo;
|
||||
class PNMTextMaker;
|
||||
class PNMImage;
|
||||
class PNMImageHeader;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : IndexImage
|
||||
// Description : An aggregate image containing several thumbnails, one
|
||||
// for each of several photos. A roll directory will
|
||||
// collect its photos into one or more IndexImages.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class IndexImage {
|
||||
public:
|
||||
IndexImage(RollDirectory *dir, int index);
|
||||
~IndexImage();
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
bool generate_reduced_html(ostream &html, Photo *photo, int photo_index,
|
||||
int pi, const Filename &roll_dir_root);
|
||||
void generate_nav_buttons(ostream &html, const Filename &prev_photo_filename,
|
||||
const Filename &next_photo_filename,
|
||||
const string &up_href);
|
||||
|
||||
static void compute_reduction(const PNMImageHeader &source_image,
|
||||
PNMImage &dest_image,
|
||||
int x_size, int y_size);
|
||||
static void draw_box(PNMImage &image);
|
||||
|
||||
static void draw_frame(PNMImage &image,
|
||||
int frame_left, int frame_top,
|
||||
int frame_width, int frame_height,
|
||||
int hole_left, int hole_top,
|
||||
int hole_width, int hole_height);
|
||||
|
||||
private:
|
||||
RollDirectory *_dir;
|
||||
int _index;
|
||||
string _name;
|
||||
|
||||
class PhotoInfo {
|
||||
public:
|
||||
int _photo_index;
|
||||
int _x_place;
|
||||
int _y_place;
|
||||
};
|
||||
|
||||
typedef pvector<PhotoInfo> Photos;
|
||||
Photos _photos;
|
||||
|
||||
int _index_x_size;
|
||||
int _index_y_size;
|
||||
string _index_basename;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const IndexImage &d) {
|
||||
d.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,296 +0,0 @@
|
|||
// Filename: indexParameters.cxx
|
||||
// Created by: drose (04Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "indexParameters.h"
|
||||
|
||||
// User parameters
|
||||
int max_index_size_array[2] = { 700, 700 };
|
||||
int thumb_size_array[2] = { 150, 150 };
|
||||
|
||||
int thumb_caption_height = 12;
|
||||
int caption_font_size = 12;
|
||||
|
||||
int thumb_space_array[2] = { 12, 12 };
|
||||
|
||||
double frame_reduction_factor = 0.75;
|
||||
int frame_outer_bevel = 2;
|
||||
int frame_inner_bevel = 1;
|
||||
|
||||
int reduced_size_array[2] = { 800, 700 };
|
||||
|
||||
Filename archive_dir;
|
||||
|
||||
Filename prev_icon;
|
||||
Filename next_icon;
|
||||
Filename up_icon;
|
||||
Filename movie_icon;
|
||||
Filename sound_icon;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: get_movie_icon
|
||||
// Description: Reads the movie icon filename and returns it as an
|
||||
// image, if possible. Returns a valid image if
|
||||
// successful, an invalid one otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const PNMImage &
|
||||
get_movie_icon() {
|
||||
static PNMImage movie_icon_image;
|
||||
static bool got_image = false;
|
||||
|
||||
if (!got_image) {
|
||||
if (!movie_icon.empty()) {
|
||||
Filename icon_filename(archive_dir, movie_icon);
|
||||
nout << "Reading " << icon_filename << "\n";
|
||||
movie_icon_image.read(icon_filename);
|
||||
}
|
||||
got_image = true;
|
||||
}
|
||||
|
||||
return movie_icon_image;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: get_sound_icon
|
||||
// Description: Reads the sound icon filename and returns it as an
|
||||
// image, if possible. Returns a valid image if
|
||||
// successful, an invalid one otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const PNMImage &
|
||||
get_sound_icon() {
|
||||
static PNMImage sound_icon_image;
|
||||
static bool got_image = false;
|
||||
|
||||
if (!got_image) {
|
||||
if (!sound_icon.empty()) {
|
||||
Filename icon_filename(archive_dir, sound_icon);
|
||||
nout << "Reading " << icon_filename << "\n";
|
||||
sound_icon_image.read(icon_filename);
|
||||
}
|
||||
got_image = true;
|
||||
}
|
||||
|
||||
return sound_icon_image;
|
||||
}
|
||||
|
||||
bool force_regenerate = false;
|
||||
bool format_rose = false;
|
||||
bool sort_date = false;
|
||||
bool dummy_mode = false;
|
||||
bool draw_frames = false;
|
||||
bool omit_roll_headers = false;
|
||||
DSearchPath cm_search;
|
||||
bool omit_full_links = false;
|
||||
bool omit_complete = false;
|
||||
bool caption_frame_numbers = false;
|
||||
|
||||
|
||||
// Computed parameters
|
||||
int thumb_count_x;
|
||||
int thumb_count_y;
|
||||
int max_thumbs;
|
||||
int actual_index_width;
|
||||
|
||||
int thumb_interior_width;
|
||||
int thumb_interior_height;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: finalize_parameters
|
||||
// Description: This is called after all user parameters have been
|
||||
// changed, to do whatever computations are required for
|
||||
// the other parameters that are based on the user
|
||||
// parameters.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
finalize_parameters() {
|
||||
thumb_count_x =
|
||||
(max_index_width - thumb_x_space) / (thumb_width + thumb_x_space);
|
||||
thumb_count_y =
|
||||
(max_index_height - thumb_y_space) / (thumb_height + thumb_caption_height + thumb_y_space);
|
||||
|
||||
max_thumbs = thumb_count_x * thumb_count_y;
|
||||
|
||||
actual_index_width = thumb_x_space + thumb_count_x * (thumb_width + thumb_x_space);
|
||||
|
||||
if (draw_frames) {
|
||||
thumb_interior_width = (int)(thumb_width * frame_reduction_factor + 0.5);
|
||||
thumb_interior_height = (int)(thumb_height * frame_reduction_factor + 0.5);
|
||||
} else {
|
||||
thumb_interior_width = thumb_width;
|
||||
thumb_interior_height = thumb_height;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: compose_href
|
||||
// Description: Combines a user-supplied prefix with a relative
|
||||
// directory to generate the appropriate href to the
|
||||
// file.
|
||||
//
|
||||
// rel_dir is the relative path to archive_dir.
|
||||
// user_prefix is the string the user indicated as the
|
||||
// relative or absolute path to the file's parent
|
||||
// directory from archive_dir. basename is the name
|
||||
// of the file, or empty if the filename is part of
|
||||
// user_prefix.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Filename
|
||||
compose_href(const Filename &rel_dir, const Filename &user_prefix,
|
||||
const Filename &basename) {
|
||||
Filename result;
|
||||
|
||||
if (user_prefix.empty()) {
|
||||
result = rel_dir;
|
||||
|
||||
} else {
|
||||
// Check to see if the user prefix begins with a URL designator,
|
||||
// like http:// or ftp://.
|
||||
size_t ui = 0;
|
||||
while (ui < user_prefix.length() && isalpha(user_prefix[ui])) {
|
||||
ui++;
|
||||
}
|
||||
bool is_url = (user_prefix.get_fullpath().substr(ui, 3) == "://");
|
||||
|
||||
if (!is_url && user_prefix.is_local()) {
|
||||
Filename rel_user_dir(rel_dir, user_prefix);
|
||||
result = rel_user_dir;
|
||||
result.standardize();
|
||||
|
||||
} else {
|
||||
result = user_prefix;
|
||||
}
|
||||
}
|
||||
|
||||
if (basename.empty()) {
|
||||
return result;
|
||||
} else {
|
||||
return Filename(result, basename);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: escape_html
|
||||
// Description: Returns the input string with all invalid characters
|
||||
// for HTML code replaced by their HTML equivalents.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string
|
||||
escape_html(const string &input) {
|
||||
static const struct {
|
||||
const char *name;
|
||||
int code;
|
||||
} tokens[] = {
|
||||
{ "amp", '&' }, { "lt", '<' }, { "gt", '>' }, { "quot", '"' },
|
||||
{ "nbsp", 160 },
|
||||
|
||||
{ "iexcl", 161 }, { "cent", 162 }, { "pound", 163 }, { "curren", 164 },
|
||||
{ "yen", 165 }, { "brvbar", 166 }, { "brkbar", 166 }, { "sect", 167 },
|
||||
{ "uml", 168 }, { "die", 168 }, { "copy", 169 }, { "ordf", 170 },
|
||||
{ "laquo", 171 }, { "not", 172 }, { "shy", 173 }, { "reg", 174 },
|
||||
{ "macr", 175 }, { "hibar", 175 }, { "deg", 176 }, { "plusmn", 177 },
|
||||
{ "sup2", 178 }, { "sup3", 179 }, { "acute", 180 }, { "micro", 181 },
|
||||
{ "para", 182 }, { "middot", 183 }, { "cedil", 184 }, { "sup1", 185 },
|
||||
{ "ordm", 186 }, { "raquo", 187 }, { "frac14", 188 }, { "frac12", 189 },
|
||||
{ "frac34", 190 }, { "iquest", 191 }, { "Agrave", 192 }, { "Aacute", 193 },
|
||||
{ "Acirc", 194 }, { "Atilde", 195 }, { "Auml", 196 }, { "Aring", 197 },
|
||||
{ "AElig", 198 }, { "Ccedil", 199 }, { "Egrave", 200 }, { "Eacute", 201 },
|
||||
{ "Ecirc", 202 }, { "Euml", 203 }, { "Igrave", 204 }, { "Iacute", 205 },
|
||||
{ "Icirc", 206 }, { "Iuml", 207 }, { "ETH", 208 }, { "Dstrok", 208 },
|
||||
{ "Ntilde", 209 }, { "Ograve", 210 }, { "Oacute", 211 }, { "Ocirc", 212 },
|
||||
{ "Otilde", 213 }, { "Ouml", 214 }, { "times", 215 }, { "Oslash", 216 },
|
||||
{ "Ugrave", 217 }, { "Uacute", 218 }, { "Ucirc", 219 }, { "Uuml", 220 },
|
||||
{ "Yacute", 221 }, { "THORN", 222 }, { "szlig", 223 }, { "agrave", 224 },
|
||||
{ "aacute", 225 }, { "acirc", 226 }, { "atilde", 227 }, { "auml", 228 },
|
||||
{ "aring", 229 }, { "aelig", 230 }, { "ccedil", 231 }, { "egrave", 232 },
|
||||
{ "eacute", 233 }, { "ecirc", 234 }, { "euml", 235 }, { "igrave", 236 },
|
||||
{ "iacute", 237 }, { "icirc", 238 }, { "iuml", 239 }, { "eth", 240 },
|
||||
{ "ntilde", 241 }, { "ograve", 242 }, { "oacute", 243 }, { "ocirc", 244 },
|
||||
{ "otilde", 245 }, { "ouml", 246 }, { "divide", 247 }, { "oslash", 248 },
|
||||
{ "ugrave", 249 }, { "uacute", 250 }, { "ucirc", 251 }, { "uuml", 252 },
|
||||
{ "yacute", 253 }, { "thorn", 254 }, { "yuml", 255 },
|
||||
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
string result;
|
||||
for (string::const_iterator ii = input.begin();
|
||||
ii != input.end();
|
||||
++ii) {
|
||||
int code = (unsigned char)(*ii);
|
||||
bool found_match = false;
|
||||
for (int i = 0; !found_match && tokens[i].name != NULL; i++) {
|
||||
if (code == tokens[i].code) {
|
||||
result += '&';
|
||||
result += tokens[i].name;
|
||||
result += ';';
|
||||
found_match = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_match) {
|
||||
result += (*ii);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if defined(HAVE_UNISTD_H) && !defined(WIN32)
|
||||
// Try to make a hard link.
|
||||
string os_source_file = source_file.to_os_specific();
|
||||
string os_dest_file = dest_file.to_os_specific();
|
||||
if (link(os_source_file.c_str(), os_dest_file.c_str()) == 0) {
|
||||
cerr << "Linked " << source_file << " to " << dest_file << "\n";
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
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,154 +0,0 @@
|
|||
// Filename: indexParameters.h
|
||||
// Created by: drose (04Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INDEXPARAMETERS_H
|
||||
#define INDEXPARAMETERS_H
|
||||
|
||||
#include "pandatoolbase.h"
|
||||
|
||||
#include "filename.h"
|
||||
#include "dSearchPath.h"
|
||||
#include "pnmImage.h"
|
||||
|
||||
// Some of these constants may be modified by command-line parameters
|
||||
// from the user.
|
||||
|
||||
// The maximum size of the index image. It will shrink vertically to
|
||||
// fit the images it contains, and it will shrink horizontally to fit
|
||||
// a complete row of images (even if it does not contain a complete
|
||||
// row). It will never be larger than this.
|
||||
extern int max_index_size_array[2];
|
||||
#define max_index_width (max_index_size_array[0])
|
||||
#define max_index_height (max_index_size_array[1])
|
||||
|
||||
// The size of the individual thumbnail images, including the frames
|
||||
// (if present). Thumbnail images are scaled to fit within this box.
|
||||
extern int thumb_size_array[2];
|
||||
#define thumb_width (thumb_size_array[0])
|
||||
#define thumb_height (thumb_size_array[1])
|
||||
|
||||
// The total number of pixels reserved for the caption under each
|
||||
// thumbnail image. This is the caption_font_size plus whatever
|
||||
// spacing should be included between the caption and the image.
|
||||
extern int thumb_caption_height;
|
||||
|
||||
// The size in pixels of the caption font. This depends on the point
|
||||
// size of the font as reported by FreeType, so the actual height of
|
||||
// the letters might be slightly lower or higher than this, depending
|
||||
// on the font.
|
||||
extern int caption_font_size;
|
||||
|
||||
// The amount of space, in pixels, between each two neighboring
|
||||
// thumbnail images, and around the overall index image.
|
||||
extern int thumb_space_array[2];
|
||||
#define thumb_x_space (thumb_space_array[0])
|
||||
#define thumb_y_space (thumb_space_array[1])
|
||||
|
||||
// The ratio by which the thumbnail images are reduced further when
|
||||
// frames are drawn, to allow room for a frame that resembles a slide
|
||||
// mount.
|
||||
extern double frame_reduction_factor;
|
||||
|
||||
// The number of pixels of thickness to draw for the frames' outer
|
||||
// bevels and inner bevels, respectively.
|
||||
extern int frame_outer_bevel;
|
||||
extern int frame_inner_bevel;
|
||||
|
||||
// The size of the reduced images on the individual image pages. The
|
||||
// source image will be scaled to fit within this rectangle.
|
||||
extern int reduced_size_array[2];
|
||||
#define reduced_width (reduced_size_array[0])
|
||||
#define reduced_height (reduced_size_array[1])
|
||||
|
||||
// The directory at the root of the output hierarchy (or as specified
|
||||
// by -a on the command line).
|
||||
extern Filename archive_dir;
|
||||
|
||||
// The filenames (or URLS) to the icon images for navigating the
|
||||
// individual image pages.
|
||||
extern Filename prev_icon;
|
||||
extern Filename next_icon;
|
||||
extern Filename up_icon;
|
||||
extern Filename movie_icon;
|
||||
extern Filename sound_icon;
|
||||
|
||||
const PNMImage &get_movie_icon();
|
||||
const PNMImage &get_sound_icon();
|
||||
|
||||
// True to regenerate every image, whether it appears to need it or
|
||||
// not.
|
||||
extern bool force_regenerate;
|
||||
|
||||
// True to use the Rose formatting convention for roll directory names.
|
||||
extern bool format_rose;
|
||||
|
||||
// True to sort roll directory names by date. Useful only with -r.
|
||||
extern bool sort_date;
|
||||
|
||||
// True to place dummy thumbnails instead of loading actual images.
|
||||
extern bool dummy_mode;
|
||||
|
||||
// True to draw frames (slide mounts) around each thumbnail image.
|
||||
extern bool draw_frames;
|
||||
|
||||
// True to avoid introducing each roll directory on the index page
|
||||
// with its own little header. This also ignored the roll.cm file if
|
||||
// it exists.
|
||||
extern bool omit_roll_headers;
|
||||
extern DSearchPath cm_search;
|
||||
|
||||
// True to omit links to the full-size source images.
|
||||
extern bool omit_full_links;
|
||||
|
||||
// True to omit complete.htm
|
||||
extern bool omit_complete;
|
||||
|
||||
// True to caption photos with just a frame number instead of the
|
||||
// whole image basename. This only works if the photo image filenames
|
||||
// consist of the roll directory name concatenated with a frame number.
|
||||
extern bool caption_frame_numbers;
|
||||
|
||||
|
||||
void finalize_parameters();
|
||||
|
||||
|
||||
|
||||
// The following parameters are all computed based on the above.
|
||||
|
||||
// The number of thumbnail images that fit across an index image,
|
||||
// horizontally and vertically.
|
||||
extern int thumb_count_x;
|
||||
extern int thumb_count_y;
|
||||
|
||||
// The total number of thumbnail images within each index image.
|
||||
extern int max_thumbs;
|
||||
|
||||
// The number of pixels wide each index image will actually be, based
|
||||
// on thumb_count_x.
|
||||
extern int actual_index_width;
|
||||
|
||||
// The actual size of the rectangle each thumbnail image must be
|
||||
// scaled into, accounting for the presence of a frame.
|
||||
extern int thumb_interior_width;
|
||||
extern int thumb_interior_height;
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
|
@ -1,738 +0,0 @@
|
|||
// Filename: indexify.cxx
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "indexify.h"
|
||||
#include "rollDirectory.h"
|
||||
#include "pnotify.h"
|
||||
#include "pnmTextMaker.h"
|
||||
#include "default_font.h"
|
||||
#include "default_index_icons.h"
|
||||
#include "indexParameters.h"
|
||||
#include "string_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Indexify::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Indexify::
|
||||
Indexify() {
|
||||
clear_runlines();
|
||||
add_runline("[opts] roll1-dir roll2-dir [roll3-dir ...]");
|
||||
add_runline("[opts] full/*");
|
||||
|
||||
set_program_description
|
||||
("This program reads a collection of directories containing photo "
|
||||
"archives (typically JPEG files), and will generate a number of "
|
||||
"thumbnail images and a series of HTML pages to browse them. It is "
|
||||
"especially useful in preparation for burning the photo archives to "
|
||||
"CD.\n\n"
|
||||
|
||||
"A number of directories is named on the command line; each "
|
||||
"directory must contain a number of image files, and all directories "
|
||||
"should be within the same parent directory. Each directory is "
|
||||
"considered a \"roll\", which may or may not correspond to a physical "
|
||||
"roll of film, and the photos within each directory are grouped "
|
||||
"correspondingly on the generated HTML pages. One common special case "
|
||||
"is in which all the roll directories are found in the subdirectory "
|
||||
"named \"full\" (e.g., the second example above) or \"reduced\". This "
|
||||
"keeps the root directory nice and clean.\n\n"
|
||||
|
||||
"If a file exists by the same name as an image file but with the "
|
||||
"extension \"cm\", that file is taken to be a HTML comment about that "
|
||||
"particular image and is inserted the HTML page for that image. "
|
||||
"Similarly, if there is a file within a roll directory with the same "
|
||||
"name as the directory itself (but with the extension \"cm\"), that file "
|
||||
"is inserted into the front page to introduce that particular roll. "
|
||||
"Finally, a file with the name of the directory, but with the extension "
|
||||
"\"ds\" may contain a brief one-line description of the directory, for "
|
||||
"the toplevel index page.\n\n"
|
||||
|
||||
"Normally, all image files with the specified extension (normally "
|
||||
"\"jpg\") within a roll directory are included in the index, and sorted "
|
||||
"into alphabetical (or numerical) order. If you wish to specify a "
|
||||
"different order, or use only a subset of the images in a directory, "
|
||||
"create a file in the roll directory with the same name as the "
|
||||
"directory itself, and the extension \"ls\". This file should "
|
||||
"simply list the filenames (with or without extension) within the "
|
||||
"roll directory in the order they should be listed. If the ls "
|
||||
"file exists but is empty, it indicates that the files should be "
|
||||
"listed in reverse order, as from a camera that loads its film "
|
||||
"upside-down.");
|
||||
|
||||
add_option
|
||||
("t", "title", 0,
|
||||
"Specifies the title to give to the front HTML page.",
|
||||
&Indexify::dispatch_string, NULL, &_front_title);
|
||||
|
||||
add_option
|
||||
("a", "archive-dir", 0,
|
||||
"Write the generated files to the indicated directory, instead of "
|
||||
"the directory above roll1-dir.",
|
||||
&Indexify::dispatch_filename, NULL, &archive_dir);
|
||||
|
||||
add_option
|
||||
("r", "relative-dir", 0,
|
||||
"When -a is specified to place the generated html files in a directory "
|
||||
"other than the default, you may need "
|
||||
"to specify how the html files will address the roll directories. This "
|
||||
"parameter specifies the relative path to the directory above the roll "
|
||||
"directories, from the directory named by -a.",
|
||||
&Indexify::dispatch_filename, NULL, &_roll_dir_root);
|
||||
|
||||
add_option
|
||||
("f", "", 0,
|
||||
"Forces the regeneration of all reduced and thumbnail images, even if "
|
||||
"image files already exist that seem to be newer than the source "
|
||||
"image files.",
|
||||
&Indexify::dispatch_none, &force_regenerate);
|
||||
|
||||
add_option
|
||||
("r", "", 0,
|
||||
"Specifies that roll directory names are encoded using the Rose "
|
||||
"convention of six digits: mmyyss, where mm and yy are the month and "
|
||||
"year, and ss is a sequence number of the roll within the month. This "
|
||||
"name will be reformatted to m-yy/s for output.",
|
||||
&Indexify::dispatch_none, &format_rose);
|
||||
|
||||
add_option
|
||||
("s", "", 0,
|
||||
"When used in conjunction with -r, requests sorting of the roll "
|
||||
"directory names by date.",
|
||||
&Indexify::dispatch_none, &sort_date);
|
||||
|
||||
add_option
|
||||
("d", "", 0,
|
||||
"Run in \"dummy\" mode; don't load any images, but instead just "
|
||||
"draw an empty box indicating where the thumbnails will be.",
|
||||
&Indexify::dispatch_none, &dummy_mode);
|
||||
|
||||
add_option
|
||||
("slide", "", 0,
|
||||
"Draw a frame, like a slide mount, around each thumbnail image.",
|
||||
&Indexify::dispatch_none, &draw_frames);
|
||||
|
||||
add_option
|
||||
("pe", "extension", 0,
|
||||
"Specifies the filename extension (without a leading dot) to identify "
|
||||
"photo files within the roll directories. This is normally jpg.",
|
||||
&Indexify::dispatch_string, NULL, &_photo_extension);
|
||||
|
||||
add_option
|
||||
("me", "extension", 0,
|
||||
"Specifies the filename extension (without a leading dot) to identify "
|
||||
"movie files within the roll directories. This is normally mov. If "
|
||||
"a file exists with the same name as a given photo but with this "
|
||||
"extension, it is taken to be a movie associated with the photo, and "
|
||||
"a link will be generated to play the movie.",
|
||||
&Indexify::dispatch_string, NULL, &_movie_extension);
|
||||
|
||||
add_option
|
||||
("se", "extension", 0,
|
||||
"Specifies the filename extension (without a leading dot) to identify "
|
||||
"sound files within the roll directories. This is normally mp3. If "
|
||||
"a file exists with the same name as a given photo but with this "
|
||||
"extension, it is taken to be a sound clip associated with the photo, "
|
||||
"and a link will be generated to play the clip.",
|
||||
&Indexify::dispatch_string, NULL, &_sound_extension);
|
||||
|
||||
add_option
|
||||
("i", "", 0,
|
||||
"Indicates that default navigation icon images should be generated "
|
||||
"into a directory called \"icons\" which will be created within the "
|
||||
"directory named by -a. This is meaningful only if -iprev, -inext, "
|
||||
"-iup, -imovie, and -isound are not explicitly specified.",
|
||||
&Indexify::dispatch_none, &_generate_icons);
|
||||
|
||||
add_option
|
||||
("omit-rh", "", 0,
|
||||
"Omits roll headers introducing each roll directory, including any "
|
||||
"headers defined in roll.cm files.",
|
||||
&Indexify::dispatch_none, &omit_roll_headers);
|
||||
|
||||
add_option
|
||||
("cmdir", "director", 0,
|
||||
"Searches in the named directory for .cm files before searching within "
|
||||
"the source archive. This option may be repeated.",
|
||||
&Indexify::dispatch_search_path, NULL, &cm_search);
|
||||
|
||||
add_option
|
||||
("omit-full", "", 0,
|
||||
"Omits links to the full-size images.",
|
||||
&Indexify::dispatch_none, &omit_full_links);
|
||||
|
||||
add_option
|
||||
("omit-complete", "", 0,
|
||||
"Omits the complete.htm index file that lists all thumbnails at once.",
|
||||
&Indexify::dispatch_none, &omit_complete);
|
||||
|
||||
add_option
|
||||
("caption", "size[,spacing]", 0,
|
||||
"Specifies the font size in pixels of the thumbnail captions. If the "
|
||||
"optional spacing parameter is included, it is the number of pixels "
|
||||
"below each thumbnail that the caption should be placed. Specify "
|
||||
"-caption 0 to disable thumbnail captions.",
|
||||
&Indexify::dispatch_caption, NULL);
|
||||
|
||||
add_option
|
||||
("fnum", "", 0,
|
||||
"Writes the frame number of each thumbnail image into the caption "
|
||||
"on the index page, instead of the image filename. This only works "
|
||||
"if the photo image filenames consist of the roll directory name "
|
||||
"concatenated with a frame number.",
|
||||
&Indexify::dispatch_none, &caption_frame_numbers);
|
||||
|
||||
add_option
|
||||
("font", "fontname", 0,
|
||||
"Specifies the filename of the font to use to generate the thumbnail "
|
||||
"captions.",
|
||||
&Indexify::dispatch_filename, NULL, &_font_filename);
|
||||
|
||||
add_option
|
||||
("fontaa", "factor", 0,
|
||||
"Specifies a scale factor to apply to the fonts used for captioning "
|
||||
"when generating text for the purpose of antialiasing the fonts a "
|
||||
"little better than FreeType can do by itself. The letters are "
|
||||
"generated large and then scaled to their proper size. Normally this "
|
||||
"should be a number in the range 3 to 4 for best effect.",
|
||||
&Indexify::dispatch_double, NULL, &_font_aa_factor);
|
||||
|
||||
add_option
|
||||
("thumb", "x,y", 0,
|
||||
"Specifies the size in pixels of the thumbnail images.",
|
||||
&Indexify::dispatch_int_pair, NULL, &thumb_width);
|
||||
|
||||
add_option
|
||||
("reduced", "x,y", 0,
|
||||
"Specifies the size in pixels of reduced images (images presented after "
|
||||
"the first click on a thumbnail).",
|
||||
&Indexify::dispatch_int_pair, NULL, &reduced_width);
|
||||
|
||||
add_option
|
||||
("space", "x,y", 0,
|
||||
"Specifies the x,y spacing between thumbnail images, in pixels.",
|
||||
&Indexify::dispatch_int_pair, NULL, &thumb_x_space);
|
||||
|
||||
add_option
|
||||
("index", "x,y", 0,
|
||||
"Specifies the size in pixels of the index images (the images that "
|
||||
"contain an index of thumbnails).",
|
||||
&Indexify::dispatch_int_pair, NULL, &max_index_width);
|
||||
|
||||
add_option
|
||||
("iprev", "filename", 0,
|
||||
"Specifies the relative pathname from the archive directory (or "
|
||||
"absolute pathname) to the \"previous\" icon.",
|
||||
&Indexify::dispatch_filename, NULL, &prev_icon);
|
||||
|
||||
add_option
|
||||
("inext", "filename", 0,
|
||||
"Specifies the relative pathname from the archive directory (or "
|
||||
"absolute pathname) to the \"next\" icon.",
|
||||
&Indexify::dispatch_filename, NULL, &next_icon);
|
||||
|
||||
add_option
|
||||
("iup", "filename", 0,
|
||||
"Specifies the relative pathname from the archive directory (or "
|
||||
"absolute pathname) to the \"up\" icon.",
|
||||
&Indexify::dispatch_filename, NULL, &up_icon);
|
||||
|
||||
add_option
|
||||
("imovie", "filename", 0,
|
||||
"Specifies the relative pathname from the archive directory (or "
|
||||
"absolute pathname) to the \"movie\" icon. This is used only if "
|
||||
"there are one or more movie files found in the directory.",
|
||||
&Indexify::dispatch_filename, NULL, &movie_icon);
|
||||
|
||||
add_option
|
||||
("isound", "filename", 0,
|
||||
"Specifies the relative pathname from the archive directory (or "
|
||||
"absolute pathname) to the \"sound\" icon. This is used only if "
|
||||
"there are one or more sound files found in the directory.",
|
||||
&Indexify::dispatch_filename, NULL, &sound_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";
|
||||
_sound_extension = "mp3";
|
||||
_text_maker = (PNMTextMaker *)NULL;
|
||||
_font_aa_factor = 4.0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Indexify::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Indexify::
|
||||
~Indexify() {
|
||||
RollDirs::iterator di;
|
||||
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
|
||||
RollDirectory *roll_dir = (*di);
|
||||
delete roll_dir;
|
||||
}
|
||||
|
||||
if (_text_maker != (PNMTextMaker *)NULL) {
|
||||
delete _text_maker;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Indexify::handle_args
|
||||
// Access: Protected, Virtual
|
||||
// Description: Does something with the additional arguments on the
|
||||
// command line (after all the -options have been
|
||||
// parsed). Returns true if the arguments are good,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool Indexify::
|
||||
handle_args(ProgramBase::Args &args) {
|
||||
if (args.empty()) {
|
||||
nout << "You must specify the roll directories containing archive photos on the command line.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
Args::const_iterator ai;
|
||||
for (ai = args.begin(); ai != args.end(); ++ai) {
|
||||
Filename filename = Filename::from_os_specific(*ai);
|
||||
filename.standardize();
|
||||
if (filename.is_directory()) {
|
||||
string basename = filename.get_basename();
|
||||
if (basename == "icons" || basename == "html" ||
|
||||
basename == "reduced" || basename == "thumbs") {
|
||||
nout << "Ignoring " << filename << "; indexify-generated directory.\n";
|
||||
|
||||
} else {
|
||||
RollDirectory *roll_dir = new RollDirectory(filename);
|
||||
_roll_dirs.push_back(roll_dir);
|
||||
}
|
||||
|
||||
} else if (filename.exists()) {
|
||||
nout << "Ignoring " << filename << "; not a directory.\n";
|
||||
|
||||
} else {
|
||||
nout << filename << " does not exist.\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class SortRollDirs {
|
||||
public:
|
||||
bool operator () (const RollDirectory *a, const RollDirectory *b) const {
|
||||
return a->sort_date_before(*b);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Indexify::post_command_line
|
||||
// Access: Protected, Virtual
|
||||
// Description: This is called after the command line has been
|
||||
// completely processed, and it gives the program a
|
||||
// chance to do some last-minute processing and
|
||||
// validation of the options and arguments. It should
|
||||
// return true if everything is fine, false if there is
|
||||
// an error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool Indexify::
|
||||
post_command_line() {
|
||||
if (_roll_dirs.empty()) {
|
||||
nout << "No roll directories.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (archive_dir.empty()) {
|
||||
// Choose a default archive directory, above the first roll directory.
|
||||
archive_dir = _roll_dirs.front()->get_dir().get_dirname();
|
||||
string parent_dirname = archive_dir.get_basename();
|
||||
if (parent_dirname == "full" || parent_dirname == "reduced") {
|
||||
// As a special case, if the subdirectory name is "full" or
|
||||
// "reduced", use the directory above that.
|
||||
archive_dir = archive_dir.get_dirname();
|
||||
}
|
||||
if (archive_dir.empty()) {
|
||||
archive_dir = ".";
|
||||
}
|
||||
}
|
||||
archive_dir.standardize();
|
||||
|
||||
if (!_roll_dir_root.empty()) {
|
||||
_roll_dir_root.standardize();
|
||||
}
|
||||
|
||||
// Sort the roll directories, if specified.
|
||||
if (format_rose && sort_date) {
|
||||
sort(_roll_dirs.begin(), _roll_dirs.end(), SortRollDirs());
|
||||
}
|
||||
|
||||
// Update the next/prev pointers in each roll directory so we can
|
||||
// browse from one to the other.
|
||||
RollDirectory *prev_roll_dir = (RollDirectory *)NULL;
|
||||
RollDirs::iterator di;
|
||||
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
|
||||
RollDirectory *roll_dir = (*di);
|
||||
if (prev_roll_dir != (RollDirectory *)NULL) {
|
||||
roll_dir->_prev = prev_roll_dir;
|
||||
prev_roll_dir->_next = roll_dir;
|
||||
}
|
||||
prev_roll_dir = roll_dir;
|
||||
}
|
||||
|
||||
if (_front_title.empty()) {
|
||||
// Supply a default title.
|
||||
if (_roll_dirs.size() == 1) {
|
||||
_front_title = _roll_dirs.front()->get_name();
|
||||
} else {
|
||||
_front_title = _roll_dirs.front()->get_name() + " through " + _roll_dirs.back()->get_name();
|
||||
}
|
||||
}
|
||||
|
||||
if (caption_font_size != 0) {
|
||||
if (!_font_filename.empty()) {
|
||||
_text_maker = new PNMTextMaker(_font_filename, 0);
|
||||
if (!_text_maker->is_valid()) {
|
||||
delete _text_maker;
|
||||
_text_maker = (PNMTextMaker *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (_text_maker == (PNMTextMaker *)NULL) {
|
||||
_text_maker = new PNMTextMaker((const char *)default_font,
|
||||
default_font_size, 0);
|
||||
if (!_text_maker->is_valid()) {
|
||||
nout << "Unable to open default font.\n";
|
||||
delete _text_maker;
|
||||
_text_maker = (PNMTextMaker *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (_text_maker != (PNMTextMaker *)NULL) {
|
||||
_text_maker->set_scale_factor(_font_aa_factor);
|
||||
_text_maker->set_pixel_size(caption_font_size);
|
||||
_text_maker->set_align(PNMTextMaker::A_center);
|
||||
}
|
||||
}
|
||||
|
||||
if (_generate_icons) {
|
||||
if (prev_icon.empty()) {
|
||||
prev_icon = Filename("icons", default_left_icon_filename);
|
||||
Filename icon_filename(archive_dir, prev_icon);
|
||||
|
||||
if (force_regenerate || !icon_filename.exists()) {
|
||||
nout << "Generating " << icon_filename << "\n";
|
||||
icon_filename.make_dir();
|
||||
icon_filename.set_binary();
|
||||
|
||||
ofstream output;
|
||||
if (!icon_filename.open_write(output)) {
|
||||
nout << "Unable to write to " << icon_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
output.write((const char *)default_left_icon, default_left_icon_len);
|
||||
}
|
||||
}
|
||||
if (next_icon.empty()) {
|
||||
next_icon = Filename("icons", default_right_icon_filename);
|
||||
Filename icon_filename(archive_dir, next_icon);
|
||||
if (force_regenerate || !icon_filename.exists()) {
|
||||
nout << "Generating " << icon_filename << "\n";
|
||||
icon_filename.make_dir();
|
||||
icon_filename.set_binary();
|
||||
|
||||
ofstream output;
|
||||
if (!icon_filename.open_write(output)) {
|
||||
nout << "Unable to write to " << icon_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
output.write((const char *)default_right_icon, default_right_icon_len);
|
||||
}
|
||||
}
|
||||
if (up_icon.empty()) {
|
||||
up_icon = Filename("icons", default_up_icon_filename);
|
||||
Filename icon_filename(archive_dir, up_icon);
|
||||
if (force_regenerate || !icon_filename.exists()) {
|
||||
nout << "Generating " << icon_filename << "\n";
|
||||
icon_filename.make_dir();
|
||||
icon_filename.set_binary();
|
||||
|
||||
ofstream output;
|
||||
if (!icon_filename.open_write(output)) {
|
||||
nout << "Unable to write to " << icon_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
output.write((const char *)default_up_icon, default_up_icon_len);
|
||||
}
|
||||
}
|
||||
if (movie_icon.empty()) {
|
||||
movie_icon = Filename("icons", default_movie_icon_filename);
|
||||
Filename icon_filename(archive_dir, movie_icon);
|
||||
if (force_regenerate || !icon_filename.exists()) {
|
||||
nout << "Generating " << icon_filename << "\n";
|
||||
icon_filename.make_dir();
|
||||
icon_filename.set_binary();
|
||||
|
||||
ofstream output;
|
||||
if (!icon_filename.open_write(output)) {
|
||||
nout << "Unable to write to " << icon_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
output.write((const char *)default_movie_icon, default_movie_icon_len);
|
||||
}
|
||||
}
|
||||
if (sound_icon.empty()) {
|
||||
sound_icon = Filename("icons", default_sound_icon_filename);
|
||||
Filename icon_filename(archive_dir, sound_icon);
|
||||
if (force_regenerate || !icon_filename.exists()) {
|
||||
nout << "Generating " << icon_filename << "\n";
|
||||
icon_filename.make_dir();
|
||||
icon_filename.set_binary();
|
||||
|
||||
ofstream output;
|
||||
if (!icon_filename.open_write(output)) {
|
||||
nout << "Unable to write to " << icon_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
output.write((const char *)default_sound_icon, default_sound_icon_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finalize_parameters();
|
||||
|
||||
|
||||
return ProgramBase::post_command_line();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Indexify::dispatch_caption
|
||||
// Access: Protected, Static
|
||||
// Description: Dispatch function for the -caption parameter, which
|
||||
// takes either one or two numbers separated by a comma,
|
||||
// representing the caption font size and the optional
|
||||
// pixel spacing of the caption under the image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool Indexify::
|
||||
dispatch_caption(const string &opt, const string &arg, void *) {
|
||||
vector_string words;
|
||||
tokenize(arg, words, ",");
|
||||
|
||||
int caption_spacing = 0;
|
||||
|
||||
bool okflag = false;
|
||||
if (words.size() == 1) {
|
||||
okflag =
|
||||
string_to_int(words[0], caption_font_size);
|
||||
|
||||
} else if (words.size() == 2) {
|
||||
okflag =
|
||||
string_to_int(words[0], caption_font_size) &&
|
||||
string_to_int(words[1], caption_spacing);
|
||||
}
|
||||
|
||||
if (!okflag) {
|
||||
nout << "-" << opt
|
||||
<< " requires one or two integers separated by a comma.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
thumb_caption_height = caption_font_size + caption_spacing;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Indexify::run
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Indexify::
|
||||
run() {
|
||||
bool all_ok = true;
|
||||
|
||||
RollDirs::iterator di;
|
||||
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
|
||||
RollDirectory *roll_dir = (*di);
|
||||
if (!roll_dir->scan(_photo_extension, _movie_extension, _sound_extension)) {
|
||||
nout << "Unable to read " << *roll_dir << "\n";
|
||||
all_ok = false;
|
||||
}
|
||||
roll_dir->collect_index_images();
|
||||
}
|
||||
|
||||
if (!all_ok) {
|
||||
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)) {
|
||||
nout << "Failure.\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Then go back and generate the HTML.
|
||||
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
|
||||
RollDirectory *roll_dir = (*di);
|
||||
if (!roll_dir->generate_html(archive_dir, _roll_dir_root)) {
|
||||
nout << "Failure.\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!omit_complete) {
|
||||
// Generate the complete index that browses all the roll directories
|
||||
// at once.
|
||||
Filename complete_filename(archive_dir, "html/complete.htm");
|
||||
nout << "Generating " << complete_filename << "\n";
|
||||
complete_filename.set_text();
|
||||
ofstream complete_html;
|
||||
if (!complete_filename.open_write(complete_html)) {
|
||||
nout << "Unable to write to " << complete_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
complete_html
|
||||
<< "<html>\n"
|
||||
<< "<head>\n"
|
||||
<< "<title>" << _front_title << "</title>\n"
|
||||
<< "</head>\n"
|
||||
<< "<body>\n"
|
||||
<< "<h1>" << _front_title << "</h1>\n";
|
||||
|
||||
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
|
||||
RollDirectory *roll_dir = (*di);
|
||||
complete_html
|
||||
<< roll_dir->get_comment_html()
|
||||
<< roll_dir->get_index_html();
|
||||
}
|
||||
|
||||
complete_html << "<p>\n";
|
||||
if (!up_icon.empty()) {
|
||||
// Use an icon to go up.
|
||||
Filename up_icon_href = compose_href("..", up_icon);
|
||||
complete_html
|
||||
<< "<a href=\"../index.htm\"><img src=\"" << up_icon_href
|
||||
<< "\" alt=\"return to index\"></a>\n";
|
||||
} else {
|
||||
// No up icon; use text to go up.
|
||||
complete_html
|
||||
<< "<br><a href=\"../index.htm\">Return to index</a>\n";
|
||||
}
|
||||
complete_html << "</p>\n";
|
||||
|
||||
complete_html
|
||||
<< "</body>\n"
|
||||
<< "</html>\n";
|
||||
}
|
||||
|
||||
// And finally, generate the index HTML file that sits on the top of
|
||||
// all of this.
|
||||
Filename index_filename(archive_dir, "index.htm");
|
||||
nout << "Generating " << index_filename << "\n";
|
||||
index_filename.set_text();
|
||||
ofstream index_html;
|
||||
if (!index_filename.open_write(index_html)) {
|
||||
nout << "Unable to write to " << index_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
index_html
|
||||
<< "<html>\n"
|
||||
<< "<head>\n"
|
||||
<< "<title>" << _front_title << "</title>\n"
|
||||
<< "</head>\n"
|
||||
<< "<body>\n"
|
||||
<< "<h1>" << _front_title << "</h1>\n"
|
||||
<< "<ul>\n";
|
||||
|
||||
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
|
||||
RollDirectory *roll_dir = (*di);
|
||||
if (!roll_dir->is_empty()) {
|
||||
index_html
|
||||
<< "<a name=\"" << roll_dir->get_basename() << "\">\n"
|
||||
<< "<li><a href=\"html/" << roll_dir->get_basename() << ".htm\">"
|
||||
<< roll_dir->get_name() << " " << escape_html(roll_dir->get_desc())
|
||||
<< "</a></li>\n";
|
||||
}
|
||||
}
|
||||
|
||||
index_html
|
||||
<< "</ul>\n";
|
||||
|
||||
if (!omit_complete) {
|
||||
index_html
|
||||
<< "<a href=\"html/complete.htm\">(complete archive)</a>\n";
|
||||
}
|
||||
|
||||
index_html
|
||||
<< "</body>\n"
|
||||
<< "</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;
|
||||
prog.parse_command_line(argc, argv);
|
||||
prog.run();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
// Filename: indexify.h
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INDEXIFY_H
|
||||
#define INDEXIFY_H
|
||||
|
||||
#include "pandatoolbase.h"
|
||||
|
||||
#include "programBase.h"
|
||||
#include "filename.h"
|
||||
#include "pvector.h"
|
||||
|
||||
class RollDirectory;
|
||||
class PNMTextMaker;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : Indexify
|
||||
// Description : A program to generate a series of thumbnail images
|
||||
// and HTML pages to view a number of image files in an
|
||||
// archive directory, before writing the archive to a
|
||||
// permanent medium like a CD.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class Indexify : public ProgramBase {
|
||||
public:
|
||||
Indexify();
|
||||
virtual ~Indexify();
|
||||
|
||||
protected:
|
||||
virtual bool handle_args(Args &args);
|
||||
virtual bool post_command_line();
|
||||
|
||||
static bool dispatch_caption(const string &opt, const string &arg, void *var);
|
||||
|
||||
public:
|
||||
void run();
|
||||
void do_generate_images();
|
||||
void do_copy_reduced();
|
||||
|
||||
string _front_title;
|
||||
Filename _roll_dir_root;
|
||||
string _photo_extension;
|
||||
string _movie_extension;
|
||||
string _sound_extension;
|
||||
Filename _font_filename;
|
||||
bool _generate_icons;
|
||||
double _font_aa_factor;
|
||||
bool _copy_reduced;
|
||||
|
||||
typedef pvector<RollDirectory *> RollDirs;
|
||||
RollDirs _roll_dirs;
|
||||
|
||||
PNMTextMaker *_text_maker;
|
||||
};
|
||||
|
||||
#endif
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 536 B |
Binary file not shown.
|
Before Width: | Height: | Size: 258 B |
Binary file not shown.
|
Before Width: | Height: | Size: 2.0 KiB |
|
|
@ -1,182 +0,0 @@
|
|||
// Filename: photo.cxx
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "photo.h"
|
||||
#include "indexParameters.h"
|
||||
#include "rollDirectory.h"
|
||||
|
||||
static const char * const standard_movie_extensions[] = {
|
||||
"mov", "avi", "mpg", "mp4", NULL
|
||||
};
|
||||
|
||||
static const char * const standard_sound_extensions[] = {
|
||||
"mp3", "wav", "ogg", NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Photo::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Photo::
|
||||
Photo(RollDirectory *dir, const Filename &basename,
|
||||
const string &movie_extension, const string &sound_extension) :
|
||||
_dir(dir),
|
||||
_basename(basename)
|
||||
{
|
||||
_name = _basename.get_basename_wo_extension();
|
||||
_frame_number = _name;
|
||||
if (caption_frame_numbers) {
|
||||
const string &dirname = _dir->get_basename();
|
||||
|
||||
// If the initial prefix of the filename is the same as the roll
|
||||
// directory, lop it off when caption_frame_numbers is in effect.
|
||||
if (_frame_number.substr(0, dirname.length()) == dirname) {
|
||||
_frame_number = _frame_number.substr(dirname.length());
|
||||
while (_frame_number.length() > 1 && _frame_number[0] == '0') {
|
||||
_frame_number = _frame_number.substr(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_full_x_size = 0;
|
||||
_full_y_size = 0;
|
||||
_reduced_x_size = 0;
|
||||
_reduced_y_size = 0;
|
||||
_has_reduced = false;
|
||||
|
||||
_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;
|
||||
|
||||
} else {
|
||||
const char * const *ext;
|
||||
for (ext = standard_movie_extensions; *ext != NULL; ++ext) {
|
||||
movie_filename.set_extension(*ext);
|
||||
if (movie_filename.exists()) {
|
||||
_movie = movie_filename.get_basename();
|
||||
_has_movie = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_has_sound = false;
|
||||
Filename sound_filename(_dir->get_dir(), _basename);
|
||||
sound_filename.set_extension(sound_extension);
|
||||
if (sound_filename.exists()) {
|
||||
_sound = sound_filename.get_basename();
|
||||
_has_sound = true;
|
||||
|
||||
} else {
|
||||
const char * const *ext;
|
||||
for (ext = standard_sound_extensions; *ext != NULL; ++ext) {
|
||||
sound_filename.set_extension(*ext);
|
||||
if (sound_filename.exists()) {
|
||||
_sound = sound_filename.get_basename();
|
||||
_has_sound = 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;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Photo::get_basename
|
||||
// Access: Public
|
||||
// Description: Returns the filename of the photo within its roll
|
||||
// directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const Filename &Photo::
|
||||
get_basename() const {
|
||||
return _basename;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Photo::get_movie
|
||||
// Access: Public
|
||||
// Description: Returns the filename of the movie associated with the
|
||||
// photo, if any.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const Filename &Photo::
|
||||
get_movie() const {
|
||||
return _movie;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Photo::get_sound
|
||||
// Access: Public
|
||||
// Description: Returns the filename of the sound clip associated
|
||||
// with the photo, if any.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const Filename &Photo::
|
||||
get_sound() const {
|
||||
return _sound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
// Description: Returns the name of the photo without its filename
|
||||
// extension.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const string &Photo::
|
||||
get_name() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Photo::get_frame_number
|
||||
// Access: Public
|
||||
// Description: Returns the string describing the photo within the
|
||||
// roll directory. This is usually the same string
|
||||
// reported by get_name(), but it may be just the frame
|
||||
// number if caption_frame_numbers is in effect.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const string &Photo::
|
||||
get_frame_number() const {
|
||||
return _frame_number;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Photo::output
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Photo::
|
||||
output(ostream &out) const {
|
||||
out << _basename;
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
// Filename: photo.h
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PHOTO_H
|
||||
#define PHOTO_H
|
||||
|
||||
#include "pandatoolbase.h"
|
||||
|
||||
#include "filename.h"
|
||||
|
||||
class RollDirectory;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : Photo
|
||||
// Description : A single photo image within a roll directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class Photo {
|
||||
public:
|
||||
Photo(RollDirectory *dir, const Filename &basename,
|
||||
const string &movie_extension, const string &sound_extension);
|
||||
|
||||
const Filename &get_basename() const;
|
||||
const Filename &get_movie() const;
|
||||
const Filename &get_sound() const;
|
||||
const Filename &get_cm() const;
|
||||
const string &get_name() const;
|
||||
const string &get_frame_number() const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
public:
|
||||
int _full_x_size;
|
||||
int _full_y_size;
|
||||
int _reduced_x_size;
|
||||
int _reduced_y_size;
|
||||
bool _has_reduced;
|
||||
bool _has_movie;
|
||||
bool _has_sound;
|
||||
bool _has_cm;
|
||||
|
||||
private:
|
||||
RollDirectory *_dir;
|
||||
Filename _basename;
|
||||
Filename _movie;
|
||||
Filename _sound;
|
||||
Filename _cm;
|
||||
string _name;
|
||||
string _frame_number;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const Photo &p) {
|
||||
p.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 526 B |
|
|
@ -1,878 +0,0 @@
|
|||
// Filename: rollDirectory.cxx
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "rollDirectory.h"
|
||||
#include "photo.h"
|
||||
#include "indexImage.h"
|
||||
#include "indent.h"
|
||||
#include "pnotify.h"
|
||||
#include "string_utils.h"
|
||||
#include "indexParameters.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <algorithm>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
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;
|
||||
}
|
||||
|
||||
_got_ds_file = false;
|
||||
_got_ls_file = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
RollDirectory::
|
||||
~RollDirectory() {
|
||||
IndexImages::iterator ii;
|
||||
for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
|
||||
IndexImage *index_image = (*ii);
|
||||
delete index_image;
|
||||
}
|
||||
|
||||
Photos::iterator pi;
|
||||
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
|
||||
Photo *photo = (*pi);
|
||||
delete photo;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_dir
|
||||
// Access: Public
|
||||
// Description: Returns the filename of the directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const Filename &RollDirectory::
|
||||
get_dir() const {
|
||||
return _dir;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_basename
|
||||
// Access: Public
|
||||
// Description: Returns the base name of the directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const string &RollDirectory::
|
||||
get_basename() const {
|
||||
return _basename;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_name
|
||||
// Access: Public
|
||||
// Description: Returns the formatted name of the directory. This is
|
||||
// often the same as the basename, but if -r is
|
||||
// specified on the command line it might be a somewhat
|
||||
// different, reformatted name. In any case, it is the
|
||||
// name of the roll as it should be presented to the
|
||||
// user.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const string &RollDirectory::
|
||||
get_name() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_desc
|
||||
// Access: Public
|
||||
// Description: Returns the one-line description for the directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const string &RollDirectory::
|
||||
get_desc() const {
|
||||
return _desc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::scan
|
||||
// Access: Public
|
||||
// Description: Scans the directory for all the listed photos.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RollDirectory::
|
||||
scan(const string &photo_extension, const string &movie_extension,
|
||||
const string &sound_extension) {
|
||||
bool reverse_order = false;
|
||||
bool explicit_list = false;
|
||||
|
||||
// Check for a .ds file, which contains a one-line description of
|
||||
// the contents of the directory.
|
||||
_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);
|
||||
}
|
||||
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";
|
||||
} else {
|
||||
// Get the words out one at a time and put just one space
|
||||
// between them.
|
||||
string word;
|
||||
ds >> word;
|
||||
while (!ds.eof() && !ds.fail()) {
|
||||
if (!_desc.empty()) {
|
||||
_desc += ' ';
|
||||
}
|
||||
_desc += word;
|
||||
word = string();
|
||||
ds >> word;
|
||||
}
|
||||
if (!word.empty()) {
|
||||
if (!_desc.empty()) {
|
||||
_desc += ' ';
|
||||
}
|
||||
_desc += word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for an .ls file in the roll directory, which may give an
|
||||
// explicit ordering, or if empty, it specifies reverse ordering.
|
||||
_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";
|
||||
} else {
|
||||
bool any_words = false;
|
||||
string word;
|
||||
ls >> word;
|
||||
while (!ls.eof() && !ls.fail()) {
|
||||
any_words = true;
|
||||
Filename try_filename(_dir, word);
|
||||
if (!try_filename.exists()) {
|
||||
try_filename = Filename(_dir, word + "." + photo_extension);
|
||||
}
|
||||
if (!try_filename.exists()) {
|
||||
try_filename = Filename(_dir, _basename + word + "." + photo_extension);
|
||||
}
|
||||
if (!try_filename.exists()) {
|
||||
try_filename = Filename(_dir, _basename + "0" + word + "." + photo_extension);
|
||||
}
|
||||
if (try_filename.exists()) {
|
||||
add_photo(try_filename.get_basename(), movie_extension,
|
||||
sound_extension);
|
||||
} else {
|
||||
nout << "Frame " << word << " not found in " << _name << "\n";
|
||||
}
|
||||
ls >> word;
|
||||
}
|
||||
|
||||
if (!any_words) {
|
||||
// An empty .ls file just means reverse the order.
|
||||
reverse_order = true;
|
||||
} else {
|
||||
// A non-empty .ls file has listed all the files we need; no
|
||||
// need to scan the directory.
|
||||
explicit_list = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!explicit_list) {
|
||||
vector_string contents;
|
||||
|
||||
if (!_dir.scan_directory(contents)) {
|
||||
nout << "Could not read " << _dir << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// We want to sort the filenames in our own way, so that
|
||||
// underscore is deemed to fall before anything else. This allows
|
||||
// the underscore, the only non-alphnumeric character we can have
|
||||
// in a filename for an iso9660 image, to stand for "before 0".
|
||||
sort(contents.begin(), contents.end(), compare_filenames);
|
||||
|
||||
if (reverse_order) {
|
||||
reverse(contents.begin(), contents.end());
|
||||
}
|
||||
|
||||
vector_string::iterator ci;
|
||||
for (ci = contents.begin(); ci != contents.end(); ++ci) {
|
||||
Filename basename = (*ci);
|
||||
if (basename.get_extension() == photo_extension) {
|
||||
add_photo(basename, movie_extension, sound_extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_photos.empty()) {
|
||||
nout << _dir << " contains no photos.\n";
|
||||
// This is not an error, just a notice.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::collect_index_images
|
||||
// Access: Public
|
||||
// Description: Groups the photos into one or more IndexImages.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RollDirectory::
|
||||
collect_index_images() {
|
||||
// Don't call this twice.
|
||||
nassertv(_index_images.empty());
|
||||
|
||||
if (is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
IndexImage *index_image = new IndexImage(this, _index_images.size());
|
||||
_index_images.push_back(index_image);
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < _photos.size(); i++) {
|
||||
if (!index_image->add_photo(i)) {
|
||||
// Oops, that one's full.
|
||||
index_image = new IndexImage(this, _index_images.size());
|
||||
_index_images.push_back(index_image);
|
||||
bool result = index_image->add_photo(i);
|
||||
nassertv(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::sort_date_before
|
||||
// Access: Public
|
||||
// Description: Returns true if the given directory name should sort
|
||||
// before the other one, assuming the Rose naming
|
||||
// convention of mmyyss is in place.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RollDirectory::
|
||||
sort_date_before(const RollDirectory &other) const {
|
||||
if (_name == _basename && other._name == other._basename) {
|
||||
// If Rose naming convention is not in place in either case, sort
|
||||
// alphabetically.
|
||||
return _basename < other._basename;
|
||||
|
||||
} else if (_name == _basename) {
|
||||
// If Rose naming convention is in place on this one and not the
|
||||
// other, it sorts first.
|
||||
return true;
|
||||
|
||||
} else if (other._name == other._basename) {
|
||||
// And vice-versa.
|
||||
return false;
|
||||
|
||||
} else {
|
||||
// Rose naming convention holds. Sort based on year first. Years
|
||||
// above 90 are deemed to belong to the previous century.
|
||||
string yy = _basename.substr(2, 2);
|
||||
string other_yy = other._basename.substr(2, 2);
|
||||
int year = atoi(yy.c_str());
|
||||
int other_year = atoi(other_yy.c_str());
|
||||
if (year < 90) {
|
||||
year += 100;
|
||||
}
|
||||
if (other_year < 90) {
|
||||
other_year += 100;
|
||||
}
|
||||
if (year != other_year) {
|
||||
return year < other_year;
|
||||
}
|
||||
|
||||
// After year, sort alphabetically.
|
||||
return _basename < other._basename;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_newest_contributing_filename
|
||||
// Access: Public
|
||||
// Description: Returns the Filename with the newest timestamp that
|
||||
// contributes to the contents of the index images in
|
||||
// this directory, if any (other than the images
|
||||
// themselves). This is used by the IndexImage code to
|
||||
// determine if it needs to regenerate the index image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const Filename &RollDirectory::
|
||||
get_newest_contributing_filename() const {
|
||||
return _newest_contributing_filename;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::is_empty
|
||||
// Access: Public
|
||||
// Description: Returns true if the directory is empty (has no
|
||||
// photos).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RollDirectory::
|
||||
is_empty() const {
|
||||
return _photos.empty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_num_photos
|
||||
// Access: Public
|
||||
// Description: Returns the number of photos in the roll.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int RollDirectory::
|
||||
get_num_photos() const {
|
||||
return _photos.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_photo
|
||||
// Access: Public
|
||||
// Description: Returns the nth photo in the roll.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Photo *RollDirectory::
|
||||
get_photo(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_photos.size(), NULL);
|
||||
return _photos[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_num_index_images
|
||||
// Access: Public
|
||||
// Description: Returns the number of index images in the roll.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int RollDirectory::
|
||||
get_num_index_images() const {
|
||||
return _index_images.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_index_image
|
||||
// Access: Public
|
||||
// Description: Returns the nth index image in the roll.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
IndexImage *RollDirectory::
|
||||
get_index_image(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_index_images.size(), NULL);
|
||||
return _index_images[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::generate_images
|
||||
// Access: Public
|
||||
// Description: Generates image files appropriate to this directory
|
||||
// to the indicated archive dir. Returns true on
|
||||
// success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RollDirectory::
|
||||
generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
|
||||
if (is_empty()) {
|
||||
return true;
|
||||
}
|
||||
nassertr(!_index_images.empty(), false);
|
||||
|
||||
IndexImages::iterator ii;
|
||||
for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
|
||||
IndexImage *index_image = (*ii);
|
||||
if (!index_image->generate_images(archive_dir, text_maker)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::generate_html
|
||||
// Access: Public
|
||||
// Description: Generates all appropriate HTML files for this
|
||||
// directory, and generate the appropriate HTML code
|
||||
// into the html strings (retrieved by
|
||||
// get_comment_html() and get_index_html()).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RollDirectory::
|
||||
generate_html(const Filename &archive_dir, const Filename &roll_dir_root) {
|
||||
if (is_empty()) {
|
||||
return true;
|
||||
}
|
||||
nassertr(!_index_images.empty(), false);
|
||||
|
||||
ostringstream comment_strm;
|
||||
comment_strm
|
||||
<< "<a name=\"" << _basename << "\">\n";
|
||||
|
||||
if (!omit_roll_headers) {
|
||||
Filename cm_filename(_basename);
|
||||
cm_filename.set_extension("cm");
|
||||
if (cm_search.is_empty() || !cm_filename.resolve_filename(cm_search)) {
|
||||
// If the cm file isn't found along the search path specified
|
||||
// via -cmdir on the command line, then look for it in the
|
||||
// appropriate source directory.
|
||||
cm_filename = Filename(_dir, cm_filename);
|
||||
}
|
||||
|
||||
if (cm_filename.exists()) {
|
||||
// If the comment file for the roll exists, insert its contents
|
||||
// here instead of the generic header.
|
||||
if (!insert_html_comment(comment_strm, cm_filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
comment_strm
|
||||
<< "<h2>" << _name << "</h2>\n";
|
||||
if (!_desc.empty()) {
|
||||
comment_strm << "<p>" << escape_html(_desc) << ".</p>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
_comment_html = comment_strm.str();
|
||||
|
||||
Filename html_dir(archive_dir, "html");
|
||||
nout << "Generating " << Filename(html_dir, _basename) << "/*\n";
|
||||
|
||||
ostringstream index_strm;
|
||||
index_strm << "<p>\n";
|
||||
IndexImages::iterator ii;
|
||||
for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
|
||||
IndexImage *index_image = (*ii);
|
||||
if (!index_image->generate_html(index_strm, archive_dir, roll_dir_root)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
index_strm << "</p>\n";
|
||||
_index_html = index_strm.str();
|
||||
|
||||
// Also generate the index html for this directory.
|
||||
Filename html_filename(html_dir, _basename);
|
||||
html_filename.set_extension("htm");
|
||||
nout << "Generating " << html_filename << "\n";
|
||||
html_filename.set_text();
|
||||
ofstream index_html;
|
||||
if (!html_filename.open_write(index_html)) {
|
||||
nout << "Unable to write to " << html_filename << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
string up_href = "../index.htm#" + _basename;
|
||||
|
||||
Filename prev_roll_filename;
|
||||
Filename next_roll_filename;
|
||||
|
||||
if (_prev != (RollDirectory *)NULL) {
|
||||
prev_roll_filename = _prev->_basename;
|
||||
prev_roll_filename.set_extension("htm");
|
||||
}
|
||||
if (_next != (RollDirectory *)NULL) {
|
||||
next_roll_filename = _next->_basename;
|
||||
next_roll_filename.set_extension("htm");
|
||||
}
|
||||
|
||||
index_html
|
||||
<< "<html>\n"
|
||||
<< "<head>\n";
|
||||
if (_desc.empty()) {
|
||||
index_html
|
||||
<< "<title>" << _name << "</title>\n";
|
||||
} else {
|
||||
index_html
|
||||
<< "<title>" << _name << " " << escape_html(_desc) << "</title>\n";
|
||||
}
|
||||
index_html
|
||||
<< "</head>\n"
|
||||
<< "<body>\n"
|
||||
<< get_comment_html();
|
||||
|
||||
generate_nav_buttons(index_html, prev_roll_filename, next_roll_filename,
|
||||
up_href);
|
||||
index_html << get_index_html();
|
||||
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
|
||||
<< "</body>\n"
|
||||
<< "</html>\n";
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_comment_html
|
||||
// Access: Public
|
||||
// Description: Returns the HTML text that describes this directory's
|
||||
// index. This is set when generate_html() returns
|
||||
// true.
|
||||
//
|
||||
// This text may be inserted into the middle of a HTML
|
||||
// page to include the imagemap that references each of
|
||||
// the images in this directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const string &RollDirectory::
|
||||
get_comment_html() const {
|
||||
return _comment_html;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::get_index_html
|
||||
// Access: Public
|
||||
// Description: Returns the HTML text that describes this directory's
|
||||
// index. This is set when generate_html() returns
|
||||
// true.
|
||||
//
|
||||
// This text may be inserted into the middle of a HTML
|
||||
// page to include the imagemap that references each of
|
||||
// the images in this directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const string &RollDirectory::
|
||||
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 (!reduced_dir.exists()) {
|
||||
cerr << "Ignoring " << reduced_dir << "; does not exist.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RollDirectory::
|
||||
output(ostream &out) const {
|
||||
out << _name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::write
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RollDirectory::
|
||||
write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level)
|
||||
<< _dir << "\n";
|
||||
|
||||
if (!_index_images.empty()) {
|
||||
// If we have any index images, output those.
|
||||
IndexImages::const_iterator ii;
|
||||
for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
|
||||
const IndexImage *index_image = (*ii);
|
||||
index_image->write(out, indent_level + 2);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Otherwise, just output the photos.
|
||||
Photos::const_iterator pi;
|
||||
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
|
||||
const Photo *photo = (*pi);
|
||||
indent(out, indent_level + 2)
|
||||
<< *photo << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::insert_html_comment
|
||||
// Access: Public, Static
|
||||
// Description: Reads the indicated comment file and inserts its
|
||||
// contents (after the header) within the indicated
|
||||
// ostream at the current point.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RollDirectory::
|
||||
insert_html_comment(ostream &html, Filename cm_filename) {
|
||||
cm_filename.set_text();
|
||||
ifstream cm;
|
||||
if (!cm_filename.open_read(cm)) {
|
||||
nout << "Unable to read " << cm_filename << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// First, scan through the file looking for <BODY> or <body>.
|
||||
string line;
|
||||
getline(cm, line);
|
||||
while (!cm.eof() && !cm.fail()) {
|
||||
string lower = downcase(line);
|
||||
size_t body = lower.find("<body>");
|
||||
if (body != string::npos) {
|
||||
return insert_html_comment_body(html, cm);
|
||||
}
|
||||
getline(cm, line);
|
||||
}
|
||||
|
||||
// We didn't find it. Insert the whole file.
|
||||
cm.clear();
|
||||
cm.seekg(0);
|
||||
int ch = cm.get();
|
||||
while (ch != EOF) {
|
||||
html.put(ch);
|
||||
ch = cm.get();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::add_photo
|
||||
// Access: Private
|
||||
// Description: Adds the photo with the indicated basename to the
|
||||
// list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RollDirectory::
|
||||
add_photo(const Filename &basename, const string &movie_extension,
|
||||
const string &sound_extension) {
|
||||
Photo *photo = new Photo(this, basename, movie_extension, sound_extension);
|
||||
_photos.push_back(photo);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::add_contributing_filename
|
||||
// Access: Private
|
||||
// Description: Specifies an additional filename that contributes to
|
||||
// the index image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RollDirectory::
|
||||
add_contributing_filename(const Filename &filename) {
|
||||
if (_newest_contributing_filename.empty() ||
|
||||
_newest_contributing_filename.compare_timestamps(filename) < 0) {
|
||||
_newest_contributing_filename = filename;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::insert_html_comment_body
|
||||
// Access: Private, Static
|
||||
// Description: Copies from the comment file up until the next
|
||||
// </body>, or until the end of file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RollDirectory::
|
||||
insert_html_comment_body(ostream &html, istream &cm) {
|
||||
string line;
|
||||
getline(cm, line);
|
||||
while (!cm.eof() && !cm.fail()) {
|
||||
string lower = downcase(line);
|
||||
size_t body = lower.find("</body>");
|
||||
if (body != string::npos) {
|
||||
// Here's the end; we're done.
|
||||
return true;
|
||||
}
|
||||
html << line << "\n";
|
||||
getline(cm, line);
|
||||
}
|
||||
|
||||
// Reached end of file; good enough.
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::format_basename
|
||||
// Access: Private, Static
|
||||
// Description: Reformats the roll directory into a user-friendly
|
||||
// name based on its encoded directory name.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string RollDirectory::
|
||||
format_basename(const string &basename) {
|
||||
if (basename.length() <= 4) {
|
||||
return basename;
|
||||
}
|
||||
|
||||
// The first two characters must be alphanumeric.
|
||||
if (!isalnum(basename[0]) || !isalnum(basename[1])) {
|
||||
return basename;
|
||||
}
|
||||
|
||||
// The next two characters must be digits.
|
||||
if (!isdigit(basename[2]) || !isdigit(basename[3])) {
|
||||
return basename;
|
||||
}
|
||||
|
||||
// If the first two were digits as well as being alphanumeric, then
|
||||
// we have mm-yy/sequence. Otherwise, we just have xxyy/sequence.
|
||||
bool mm_is_month = (isdigit(basename[0]) && isdigit(basename[1]));
|
||||
|
||||
string mm = basename.substr(0, 2);
|
||||
string yy = basename.substr(2, 2);
|
||||
string ss = basename.substr(4);
|
||||
|
||||
if (mm_is_month && mm[0] == '0') {
|
||||
mm = mm[1];
|
||||
}
|
||||
while (ss.length() > 1 && ss[0] == '0') {
|
||||
ss = ss.substr(1);
|
||||
}
|
||||
|
||||
if (mm_is_month) {
|
||||
return mm + "-" + yy + "/" + ss;
|
||||
} else {
|
||||
return mm + yy + "/" + ss;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::generate_nav_buttons
|
||||
// Access: Private, Static
|
||||
// Description: Outputs the HTML code to generate the next, prev,
|
||||
// up buttons when viewing each reduced image.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RollDirectory::
|
||||
generate_nav_buttons(ostream &html, const Filename &prev_roll_filename,
|
||||
const Filename &next_roll_filename,
|
||||
const string &up_href) {
|
||||
html << "<p>\n";
|
||||
|
||||
bool first_icons = false;
|
||||
if (!prev_icon.empty() && !next_icon.empty()) {
|
||||
first_icons = true;
|
||||
// Use icons to go forward and back.
|
||||
Filename prev_icon_href = compose_href("..", prev_icon);
|
||||
if (prev_roll_filename.empty()) {
|
||||
html << "<img src=\"" << prev_icon_href << "\" alt=\"No previous roll\">\n";
|
||||
} else {
|
||||
html << "<a href=\"" << prev_roll_filename
|
||||
<< "\"><img src=\"" << prev_icon_href << "\" alt=\"previous\"></a>\n";
|
||||
}
|
||||
|
||||
Filename next_icon_href = compose_href("..", next_icon);
|
||||
if (next_roll_filename.empty()) {
|
||||
html << "<img src=\"" << next_icon_href << "\" alt=\"No next roll\">\n";
|
||||
} else {
|
||||
html << "<a href=\"" << next_roll_filename
|
||||
<< "\"><img src=\"" << next_icon_href << "\" alt=\"next\"></a>\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
// No prev/next icons; use text to go forward and back.
|
||||
if (prev_roll_filename.empty()) {
|
||||
html << "(This is the first roll.)\n";
|
||||
} else {
|
||||
html << "<a href=\"" << prev_roll_filename
|
||||
<< "\">Back to previous roll</a>\n";
|
||||
}
|
||||
|
||||
if (next_roll_filename.empty()) {
|
||||
html << "<br>(This is the last roll.)\n";
|
||||
} else {
|
||||
html << "<br><a href=\"" << next_roll_filename
|
||||
<< "\">On to next roll</a>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!up_href.empty()) {
|
||||
if (!up_icon.empty()) {
|
||||
// Use an icon to go up.
|
||||
if (!first_icons) {
|
||||
html << "<br>";
|
||||
} else {
|
||||
html << " ";
|
||||
}
|
||||
Filename up_icon_href = compose_href("..", up_icon);
|
||||
html << "<a href=\"" << up_href
|
||||
<< "\"><img src=\"" << up_icon_href << "\" alt=\"return to index\"></a>\n";
|
||||
} else {
|
||||
// No up icon; use text to go up.
|
||||
html << "<br><a href=\"" << up_href
|
||||
<< "\">Return to index</a>\n";
|
||||
}
|
||||
}
|
||||
html << "</p>\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RollDirectory::compare_filenames
|
||||
// Access: Private, Static
|
||||
// Description: Returns true if filename a sorts before filename b,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool RollDirectory::
|
||||
compare_filenames(const string &a, const string &b) {
|
||||
size_t i = 0;
|
||||
size_t min_length = min(a.length(), b.length());
|
||||
while (i < min_length) {
|
||||
char achar = a[i];
|
||||
char bchar = b[i];
|
||||
if (achar != bchar) {
|
||||
if (achar == '_') {
|
||||
return true;
|
||||
} else if (bchar == '_') {
|
||||
return false;
|
||||
} else {
|
||||
return achar < bchar;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
return a.length() < b.length();
|
||||
}
|
||||
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
// Filename: rollDirectory.h
|
||||
// Created by: drose (03Apr02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ROLLDIRECTORY_H
|
||||
#define ROLLDIRECTORY_H
|
||||
|
||||
#include "pandatoolbase.h"
|
||||
|
||||
#include "filename.h"
|
||||
#include "pvector.h"
|
||||
|
||||
class Photo;
|
||||
class IndexImage;
|
||||
class PNMTextMaker;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : RollDirectory
|
||||
// Description : A representation of a single directory containing one
|
||||
// or more photos.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class RollDirectory {
|
||||
public:
|
||||
RollDirectory(const Filename &dir);
|
||||
~RollDirectory();
|
||||
|
||||
const Filename &get_dir() const;
|
||||
const string &get_basename() const;
|
||||
const string &get_name() const;
|
||||
const string &get_desc() const;
|
||||
bool scan(const string &photo_extension, const string &movie_extension,
|
||||
const string &sound_extension);
|
||||
void collect_index_images();
|
||||
|
||||
bool sort_date_before(const RollDirectory &other) const;
|
||||
|
||||
const Filename &get_newest_contributing_filename() const;
|
||||
|
||||
bool is_empty() const;
|
||||
int get_num_photos() const;
|
||||
Photo *get_photo(int n) const;
|
||||
|
||||
int get_num_index_images() const;
|
||||
IndexImage *get_index_image(int n) const;
|
||||
|
||||
bool generate_images(const Filename &archive_dir, PNMTextMaker *text_maker);
|
||||
bool generate_html(const Filename &archive_dir,
|
||||
const Filename &roll_dir_root);
|
||||
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;
|
||||
|
||||
static bool insert_html_comment(ostream &html, Filename cm_filename);
|
||||
|
||||
private:
|
||||
void add_photo(const Filename &basename, const string &movie_extension,
|
||||
const string &sound_extension);
|
||||
void add_contributing_filename(const Filename &filename);
|
||||
static bool insert_html_comment_body(ostream &html, istream &cm);
|
||||
static string format_basename(const string &basename);
|
||||
void generate_nav_buttons(ostream &html,
|
||||
const Filename &prev_roll_filename,
|
||||
const Filename &next_roll_filename,
|
||||
const string &up_href);
|
||||
static bool compare_filenames(const string &a, const string &b);
|
||||
|
||||
public:
|
||||
RollDirectory *_prev;
|
||||
RollDirectory *_next;
|
||||
|
||||
private:
|
||||
Filename _dir;
|
||||
string _basename;
|
||||
string _name;
|
||||
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;
|
||||
|
||||
typedef pvector<IndexImage *> IndexImages;
|
||||
IndexImages _index_images;
|
||||
|
||||
string _comment_html;
|
||||
string _index_html;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const RollDirectory &d) {
|
||||
d.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 310 B |
Binary file not shown.
|
Before Width: | Height: | Size: 549 B |
|
|
@ -1,10 +0,0 @@
|
|||
#begin ss_lib_target
|
||||
#define TARGET pandaappbase
|
||||
|
||||
#define SOURCES \
|
||||
pandaappbase.cxx pandaappbase.h pandaappsymbols.h
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
pandaappbase.h pandaappsymbols.h
|
||||
|
||||
#end ss_lib_target
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// Filename: pandaappbase.cxx
|
||||
// Created by: drose (15Sep00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pandaappbase.h"
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
// Filename: pandaappbase.h
|
||||
// Created by: drose (12Sep00)
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* This file is included at the beginning of every header file and/or
|
||||
C or C++ file. It must be compilable for C as well as C++ files,
|
||||
so no C++-specific code or syntax can be put here. */
|
||||
|
||||
#ifndef PANDAAPPBASE_H
|
||||
#define PANDAAPPBASE_H
|
||||
|
||||
#include "pandatoolbase.h"
|
||||
#include "pandaappsymbols.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/* Filename: pandaappsymbols.h
|
||||
* Created by: drose (26Apr01)
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef PANDAAPPSYMBOLS_H
|
||||
#define PANDAAPPSYMBOLS_H
|
||||
|
||||
/* See dtoolsymbols.h for a rant on the purpose of this file. */
|
||||
|
||||
#if defined(WIN32_VC) && !defined(CPPPARSER) && !defined(LINK_ALL_STATIC)
|
||||
|
||||
#else /* !WIN32_VC */
|
||||
|
||||
#endif /* WIN32_VC */
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue