summaryrefslogtreecommitdiffstats
path: root/kfile-plugins/ps/gscreator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kfile-plugins/ps/gscreator.cpp')
-rw-r--r--kfile-plugins/ps/gscreator.cpp619
1 files changed, 0 insertions, 619 deletions
diff --git a/kfile-plugins/ps/gscreator.cpp b/kfile-plugins/ps/gscreator.cpp
deleted file mode 100644
index c664947b..00000000
--- a/kfile-plugins/ps/gscreator.cpp
+++ /dev/null
@@ -1,619 +0,0 @@
-/* This file is part of the KDE libraries
- Copyright (C) 2001 Malte Starostik <[email protected]>
-
- Handling of EPS previews Copyright (C) 2003 Philipp Hullmann <[email protected]>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/* This function gets a path of a DVI, EPS, PS or PDF file and
- produces a PNG-Thumbnail which is stored as a TQImage
-
- The program works as follows
-
- 1. Test if file is a DVI file
-
- 2. Create a child process (1), in which the
- file is to be changed into a PNG
-
- 3. Child-process (1) :
-
- 4. If file is DVI continue with 6
-
- 5. If file is no DVI continue with 9
-
- 6. Create another child process (2), in which the DVI is
- turned into PS using dvips
-
- 7. Parent process (2) :
- Turn the recently created PS file into a PNG file using gs
-
- 8. continue with 10
-
- 9. Turn the PS,PDF or EPS file into a PNG file using gs
-
- 10. Parent process (1)
- store data in a TQImage
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <signal.h>
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <kdemacros.h>
-
-#include <tqcolor.h>
-#include <tqfile.h>
-#include <tqimage.h>
-#include <tqregexp.h>
-
-
-#include "gscreator.h"
-#include "dscparse_adapter.h"
-#include "dscparse.h"
-
-extern "C"
-{
- KDE_EXPORT ThumbCreator *new_creator()
- {
- return new GSCreator;
- }
-}
-
-// This PS snippet will be prepended to the actual file so that only
-// the first page is output.
-static const char *psprolog =
- "%!PS-Adobe-3.0\n"
- "/.showpage.orig /showpage load def\n"
- "/.showpage.firstonly {\n"
- " .showpage.orig\n"
- " quit\n"
- "} def\n"
- "/showpage { .showpage.firstonly } def\n";
-
-// This is the code recommended by Adobe tech note 5002 for including
-// EPS files.
-static const char *epsprolog =
- "%!PS-Adobe-3.0\n"
- "userdict begin /pagelevel save def /showpage { } def\n"
- "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit\n"
- "[ ] 0 setdash newpath false setoverprint false setstrokeadjust\n";
-
-static const char * gsargs_ps[] = {
- "gs",
- "-sDEVICE=png16m",
- "-sOutputFile=-",
- "-dSAFER",
- "-dPARANOIDSAFER",
- "-dNOPAUSE",
- "-dFirstPage=1",
- "-dLastPage=1",
- "-q",
- "-",
- 0, // file name
- "-c",
- "showpage",
- "-c",
- "quit",
- 0
-};
-
-static const char * gsargs_eps[] = {
- "gs",
- "-sDEVICE=png16m",
- "-sOutputFile=-",
- "-dSAFER",
- "-dPARANOIDSAFER",
- "-dNOPAUSE",
- 0, // page size
- 0, // resolution
- "-q",
- "-",
- 0, // file name
- "-c",
- "pagelevel",
- "-c",
- "restore",
- "-c",
- "end",
- "-c",
- "showpage",
- "-c",
- "quit",
- 0
-};
-
-static const char *dvipsargs[] = {
- "dvips",
- "-n",
- "1",
- "-q",
- "-o",
- "-",
- 0, // file name
- 0
-};
-
-static bool correctDVI(const TQString& filename);
-
-
-namespace {
- bool got_sig_term = false;
- void handle_sigterm( int ) {
- got_sig_term = true;
- }
-}
-
-
-bool GSCreator::create(const TQString &path, int width, int height, TQImage &img)
-{
-// The code in the loop (when testing whether got_sig_term got set)
-// should read some variation of:
-// parentJob()->wasKilled()
-//
-// Unfortunatelly, that's currently impossible without breaking BIC.
-// So we need to catch the signal ourselves.
-// Otherwise, on certain funny PS files (for example
-// http://www.tjhsst.edu/~Eedanaher/pslife/life.ps )
-// gs would run forever after we were dead.
-// #### Reconsider for KDE 4 ###
-// (24/12/03 - luis_pedro)
-//
- typedef void ( *sighandler_t )( int );
- // according to linux's "man signal" the above typedef is a gnu extension
- sighandler_t oldhandler = signal( SIGTERM, handle_sigterm );
-
- int input[2];
- int output[2];
- int dvipipe[2];
-
- TQByteArray data(1024);
-
- bool ok = false;
-
- // Test if file is DVI
- bool no_dvi =!correctDVI(path);
-
- if (pipe(input) == -1) {
- return false;
- }
- if (pipe(output) == -1) {
- close(input[0]);
- close(input[1]);
- return false;
- }
-
- KDSC dsc;
- endComments = false;
- dsc.setCommentHandler(this);
-
- if (no_dvi)
- {
- FILE* fp = fopen(TQFile::encodeName(path), "r");
- if (fp == 0) return false;
-
- char buf[4096];
- int count;
- while ((count = fread(buf, sizeof(char), 4096, fp)) != 0
- && !endComments) {
- dsc.scanData(buf, count);
- }
- fclose(fp);
-
- if (dsc.pjl() || dsc.ctrld()) {
- // this file is a mess.
- return false;
- }
- }
-
- const bool is_encapsulated = no_dvi &&
- (path.find(TQRegExp("\\.epsi?$", false, false)) > 0) &&
- (dsc.bbox()->width() > 0) && (dsc.bbox()->height() > 0) &&
- (dsc.page_count() <= 1);
-
- char translation[64] = "";
- char pagesize[32] = "";
- char resopt[32] = "";
- std::auto_ptr<KDSCBBOX> bbox = dsc.bbox();
- if (is_encapsulated) {
- // GhostScript's rendering at the extremely low resolutions
- // required for thumbnails leaves something to be desired. To
- // get nicer images, we render to four times the required
- // resolution and let TQImage scale the result.
- const int hres = (width * 72) / bbox->width();
- const int vres = (height * 72) / bbox->height();
- const int resolution = (hres > vres ? vres : hres) * 4;
- const int gswidth = ((bbox->urx() - bbox->llx()) * resolution) / 72;
- const int gsheight = ((bbox->ury() - bbox->lly()) * resolution) / 72;
-
- snprintf(pagesize, 31, "-g%ix%i", gswidth, gsheight);
- snprintf(resopt, 31, "-r%i", resolution);
- snprintf(translation, 63,
- " 0 %i sub 0 %i sub translate\n", bbox->llx(),
- bbox->lly());
- }
-
- const CDSC_PREVIEW_TYPE previewType =
- static_cast<CDSC_PREVIEW_TYPE>(dsc.preview());
-
- switch (previewType) {
- case CDSC_TIFF:
- case CDSC_WMF:
- case CDSC_PICT:
- // FIXME: these should take precedence, since they can hold
- // color previews, which EPSI can't (or can it?).
- break;
- case CDSC_EPSI:
- {
- const int xscale = bbox->width() / width;
- const int yscale = bbox->height() / height;
- const int scale = xscale < yscale ? xscale : yscale;
- if (getEPSIPreview(path,
- dsc.beginpreview(),
- dsc.endpreview(),
- img,
- bbox->width() / scale,
- bbox->height() / scale))
- return true;
- // If the preview extraction routine fails, gs is used to
- // create a thumbnail.
- }
- break;
- case CDSC_NOPREVIEW:
- default:
- // need to run ghostscript in these cases
- break;
- }
-
- pid_t pid = fork();
- if (pid == 0) {
- // Child process (1)
-
- // close(STDERR_FILENO);
-
- // find first zero entry in gsargs and put the filename
- // or - (stdin) there, if DVI
- const char **gsargs = gsargs_ps;
- const char **arg = gsargs;
-
- if (no_dvi && is_encapsulated) {
- gsargs = gsargs_eps;
- arg = gsargs;
-
- // find first zero entry and put page size there
- while (*arg) ++arg;
- *arg = pagesize;
-
- // find second zero entry and put resolution there
- while (*arg) ++arg;
- *arg = resopt;
- }
-
- // find next zero entry and put the filename there
- TQCString fname = TQFile::encodeName( path );
- while (*arg)
- ++arg;
- if( no_dvi )
- *arg = fname.data();
- else
- *arg = "-";
-
- // find first zero entry in dvipsargs and put the filename there
- arg = dvipsargs;
- while (*arg)
- ++arg;
- *arg = fname.data();
-
- if( !no_dvi ){
- pipe(dvipipe);
- pid_t pid_two = fork();
- if( pid_two == 0 ){
- // Child process (2), reopen stdout on the pipe "dvipipe" and exec dvips
-
- close(input[0]);
- close(input[1]);
- close(output[0]);
- close(output[1]);
- close(dvipipe[0]);
-
- dup2( dvipipe[1], STDOUT_FILENO);
-
- execvp(dvipsargs[0], const_cast<char *const *>(dvipsargs));
- exit(1);
- }
- else if(pid_two != -1){
- close(input[1]);
- close(output[0]);
- close(dvipipe[1]);
-
- dup2( dvipipe[0], STDIN_FILENO);
- dup2( output[1], STDOUT_FILENO);
-
- execvp(gsargs[0], const_cast<char *const *>(gsargs));
- exit(1);
- }
- else{
- // fork() (2) failed, close these
- close(dvipipe[0]);
- close(dvipipe[1]);
- }
-
- }
- else if( no_dvi ){
- // Reopen stdin/stdout on the pipes and exec gs
- close(input[1]);
- close(output[0]);
-
- dup2(input[0], STDIN_FILENO);
- dup2(output[1], STDOUT_FILENO);
-
- execvp(gsargs[0], const_cast<char *const *>(gsargs));
- exit(1);
- }
- }
- else if (pid != -1) {
- // Parent process, write first-page-only-hack (the hack is not
- // used if DVI) and read the png output
- close(input[0]);
- close(output[1]);
- const char *prolog;
- if (is_encapsulated)
- prolog = epsprolog;
- else
- prolog = psprolog;
- int count = write(input[1], prolog, strlen(prolog));
- if (is_encapsulated)
- write(input[1], translation, strlen(translation));
-
- close(input[1]);
- if (count == static_cast<int>(strlen(prolog))) {
- int offset = 0;
- while (!ok) {
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(output[0], &fds);
- struct timeval tv;
- tv.tv_sec = 20;
- tv.tv_usec = 0;
-
- got_sig_term = false;
- if (select(output[0] + 1, &fds, 0, 0, &tv) <= 0) {
- if ( ( errno == EINTR || errno == EAGAIN ) && !got_sig_term ) continue;
- break; // error, timeout or master wants us to quit (SIGTERM)
- }
- if (FD_ISSET(output[0], &fds)) {
- count = read(output[0], data.data() + offset, 1024);
- if (count == -1)
- break;
- else
- if (count) // prepare for next block
- {
- offset += count;
- data.resize(offset + 1024);
- }
- else // got all data
- {
- data.resize(offset);
- ok = true;
- }
- }
- }
- }
- if (!ok) // error or timeout, gs probably didn't exit yet
- {
- kill(pid, SIGTERM);
- }
-
- int status = 0;
- if (waitpid(pid, &status, 0) != pid || (status != 0 && status != 256) )
- ok = false;
- }
- else {
- // fork() (1) failed, close these
- close(input[0]);
- close(input[1]);
- close(output[1]);
- }
- close(output[0]);
-
- int l = img.loadFromData( data );
-
- if ( got_sig_term &&
- oldhandler != SIG_ERR &&
- oldhandler != SIG_DFL &&
- oldhandler != SIG_IGN ) {
- oldhandler( SIGTERM ); // propagate the signal. Other things might rely on it
- }
- if ( oldhandler != SIG_ERR ) signal( SIGTERM, oldhandler );
-
- return ok && l;
-}
-
-ThumbCreator::Flags GSCreator::flags() const
-{
- return static_cast<Flags>(DrawFrame);
-}
-
-void GSCreator::comment(Name name)
-{
- switch (name) {
- case EndPreview:
- case BeginProlog:
- case Page:
- endComments = true;
- break;
-
- default:
- break;
- }
-}
-
-// Quick function to check if the filename corresponds to a valid DVI
-// file. Returns true if <filename> is a DVI file, false otherwise.
-
-static bool correctDVI(const TQString& filename)
-{
- TQFile f(filename);
- if (!f.open(IO_ReadOnly))
- return FALSE;
-
- unsigned char test[4];
- if ( f.readBlock( (char *)test,2)<2 || test[0] != 247 || test[1] != 2 )
- return FALSE;
-
- int n = f.size();
- if ( n < 134 ) // Too short for a dvi file
- return FALSE;
- f.at( n-4 );
-
- unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf };
-
- if ( f.readBlock( (char *)test, 4 )<4 || strncmp( (char *)test, (char*) trailer, 4 ) )
- return FALSE;
- // We suppose now that the dvi file is complete and OK
- return TRUE;
-}
-
-bool GSCreator::getEPSIPreview(const TQString &path, long start, long
- end, TQImage &outimg, int imgwidth, int imgheight)
-{
- FILE *fp;
- fp = fopen(TQFile::encodeName(path), "r");
- if (fp == 0) return false;
-
- const long previewsize = end - start + 1;
-
- char *buf = (char *) malloc(previewsize);
- fseek(fp, start, SEEK_SET);
- int count = fread(buf, sizeof(char), previewsize - 1, fp);
- fclose(fp);
- buf[previewsize - 1] = 0;
- if (count != previewsize - 1)
- {
- free(buf);
- return false;
- }
-
- TQString previewstr = TQString::fromLatin1(buf);
- free(buf);
-
- int offset = 0;
- while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++;
- int digits = 0;
- while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++;
- int width = previewstr.mid(offset, digits).toInt();
- offset += digits + 1;
- while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++;
- digits = 0;
- while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++;
- int height = previewstr.mid(offset, digits).toInt();
- offset += digits + 1;
- while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++;
- digits = 0;
- while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++;
- int depth = previewstr.mid(offset, digits).toInt();
-
- // skip over the rest of the BeginPreview comment
- while ((offset < previewsize) &&
- previewstr[offset] != '\n' &&
- previewstr[offset] != '\r') offset++;
- while ((offset < previewsize) && previewstr[offset] != '%') offset++;
-
- unsigned int imagedepth;
- switch (depth) {
- case 1:
- case 2:
- case 4:
- case 8:
- imagedepth = 8;
- break;
- case 12: // valid, but not (yet) supported
- default: // illegal value
- return false;
- }
-
- unsigned int colors = (1U << depth);
- TQImage img(width, height, imagedepth, colors);
- img.setAlphaBuffer(false);
-
- if (imagedepth <= 8) {
- for (unsigned int gray = 0; gray < colors; gray++) {
- unsigned int grayvalue = (255U * (colors - 1 - gray)) /
- (colors - 1);
- img.setColor(gray, tqRgb(grayvalue, grayvalue, grayvalue));
- }
- }
-
- const unsigned int bits_per_scan_line = width * depth;
- unsigned int bytes_per_scan_line = bits_per_scan_line / 8;
- if (bits_per_scan_line % 8) bytes_per_scan_line++;
- const unsigned int bindatabytes = height * bytes_per_scan_line;
- TQMemArray<unsigned char> bindata(bindatabytes);
-
- for (unsigned int i = 0; i < bindatabytes; i++) {
- if (offset >= previewsize)
- return false;
-
- while (!isxdigit(previewstr[offset].latin1()) &&
- offset < previewsize)
- offset++;
-
- bool ok = false;
- bindata[i] = static_cast<unsigned char>(previewstr.mid(offset, 2).toUInt(&ok, 16));
- if (!ok)
- return false;
-
- offset += 2;
- }
-
- for (int scanline = 0; scanline < height; scanline++) {
- unsigned char *scanlineptr = img.scanLine(scanline);
-
- for (int pixelindex = 0; pixelindex < width; pixelindex++) {
- unsigned char pixelvalue = 0;
- const unsigned int bitoffset =
- scanline * bytes_per_scan_line * 8U + pixelindex * depth;
- for (int depthindex = 0; depthindex < depth;
- depthindex++) {
- const unsigned int byteindex = (bitoffset + depthindex) / 8U;
- const unsigned int bitindex =
- 7 - ((bitoffset + depthindex) % 8U);
- const unsigned char bitvalue =
- (bindata[byteindex] & static_cast<unsigned char>(1U << bitindex)) >> bitindex;
- pixelvalue |= (bitvalue << depthindex);
- }
- scanlineptr[pixelindex] = pixelvalue;
- }
- }
-
- outimg = img.convertDepth(32).smoothScale(imgwidth, imgheight);
-
- return true;
-}