TiffWriter.cc 6.6 KB
Newer Older
1 2 3 4 5 6
//========================================================================
//
// TiffWriter.cc
//
// This file is licensed under the GPLv2 or later
//
7
// Copyright (C) 2010, 2012 William Bader <williambader@hotmail.com>
Albert Astals Cid's avatar
Albert Astals Cid committed
8
// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
Albert Astals Cid's avatar
Albert Astals Cid committed
9
// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
Albert Astals Cid's avatar
Albert Astals Cid committed
10
// Copyright (C) 2012 Pino Toscano <pino@kde.org>
11
// Copyright (C) 2014 Steven Lee <roc.sky@gmail.com>
12 13 14 15 16 17 18 19 20
//
//========================================================================

#include "TiffWriter.h"

#if ENABLE_LIBTIFF

#include <string.h>

21 22 23 24
#ifdef _WIN32
#include <io.h>
#endif

25 26 27 28 29 30 31 32 33 34 35 36
extern "C" {
#include <tiffio.h>
}

struct TiffWriterPrivate {
  TIFF *f;				// LibTiff file context
  int numRows;				// number of rows in the image
  int curRow;				// number of rows written
  const char *compressionString;	// compression type
  TiffWriter::Format format;		// format of image data
};

37 38
TiffWriter::~TiffWriter()
{
39
  delete priv;
40 41
}

42
TiffWriter::TiffWriter(Format formatA)
43
{
44 45 46 47 48 49
  priv = new TiffWriterPrivate;
  priv->f = NULL;
  priv->numRows = 0;
  priv->curRow = 0;
  priv->compressionString = NULL;
  priv->format = formatA;
50 51 52 53 54 55
}

// Set the compression type

void TiffWriter::setCompressionString(const char *compressionStringArg)
{
56
  priv->compressionString = compressionStringArg;
57 58 59 60 61 62 63
}

// Write a TIFF file.

bool TiffWriter::init(FILE *openedFile, int width, int height, int hDPI, int vDPI)
{
  unsigned int compression;
Albert Astals Cid's avatar
Albert Astals Cid committed
64
  uint16 photometric = 0;
65 66
  uint32 rowsperstrip = (uint32) -1;
  int bitspersample;
Albert Astals Cid's avatar
Albert Astals Cid committed
67
  uint16 samplesperpixel = 0;
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
  const struct compression_name_tag {
    const char *compressionName;		// name of the compression option from the command line
    unsigned int compressionCode;		// internal libtiff code
    const char *compressionDescription;		// descriptive name
  } compressionList[] = {
    { "none",	COMPRESSION_NONE,	"no compression" },
    { "ccittrle", COMPRESSION_CCITTRLE,	"CCITT modified Huffman RLE" },
    { "ccittfax3", COMPRESSION_CCITTFAX3,"CCITT Group 3 fax encoding" },
    { "ccittt4", COMPRESSION_CCITT_T4,	"CCITT T.4 (TIFF 6 name)" },
    { "ccittfax4", COMPRESSION_CCITTFAX4, "CCITT Group 4 fax encoding" },
    { "ccittt6", COMPRESSION_CCITT_T6,	"CCITT T.6 (TIFF 6 name)" },
    { "lzw",	COMPRESSION_LZW,	"Lempel-Ziv  & Welch" },
    { "ojpeg",	COMPRESSION_OJPEG,	"!6.0 JPEG" },
    { "jpeg",	COMPRESSION_JPEG,	"%JPEG DCT compression" },
    { "next",	COMPRESSION_NEXT,	"NeXT 2-bit RLE" },
    { "packbits", COMPRESSION_PACKBITS,	"Macintosh RLE" },
    { "ccittrlew", COMPRESSION_CCITTRLEW, "CCITT modified Huffman RLE w/ word alignment" },
    { "deflate", COMPRESSION_DEFLATE,	"Deflate compression" },
    { "adeflate", COMPRESSION_ADOBE_DEFLATE, "Deflate compression, as recognized by Adobe" },
    { "dcs",	COMPRESSION_DCS,	"Kodak DCS encoding" },
    { "jbig",	COMPRESSION_JBIG,	"ISO JBIG" },
    { "jp2000",	COMPRESSION_JP2000,	"Leadtools JPEG2000" },
    { NULL,	0,			NULL }
  };

  // Initialize

95 96
  priv->f = NULL;
  priv->curRow = 0;
97 98 99

  // Store the number of rows

100
  priv->numRows = height;
101 102 103 104 105

  // Set the compression

  compression = COMPRESSION_NONE;

106
  if (priv->compressionString == NULL || strcmp(priv->compressionString, "") == 0) {
107 108 109 110
    compression = COMPRESSION_NONE;
  } else {
    int i;
    for (i = 0; compressionList[i].compressionName != NULL; i++) {
111
      if (strcmp(priv->compressionString, compressionList[i].compressionName) == 0) {
112 113 114 115 116
	compression = compressionList[i].compressionCode;
	break;
      }
    }
    if (compressionList[i].compressionName == NULL) {
117
      fprintf(stderr, "TiffWriter: Unknown compression type '%.10s', using 'none'.\n", priv->compressionString);
118 119 120 121 122 123 124
      fprintf(stderr, "Known compression types (the tiff library might not support every type)\n");
      for (i = 0; compressionList[i].compressionName != NULL; i++) {
	fprintf(stderr, "%10s %s\n", compressionList[i].compressionName, compressionList[i].compressionDescription);
      }
    }
  }

125
  // Set bits per sample, samples per pixel, and photometric type from format
126

127
  bitspersample = (priv->format == MONOCHROME ? 1 : 8);
128

129
  switch (priv->format) {
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    case MONOCHROME:
    case GRAY:
      samplesperpixel = 1;
      photometric = PHOTOMETRIC_MINISBLACK;
      break;

    case RGB:
      samplesperpixel = 3;
      photometric = PHOTOMETRIC_RGB;
      break;

    case RGBA_PREMULTIPLIED:
      samplesperpixel = 4;
      photometric = PHOTOMETRIC_RGB;
      break;

    case CMYK:
      samplesperpixel = 4;
      photometric = PHOTOMETRIC_SEPARATED;
      break;
150 151 152 153 154 155 156 157 158
  }

  // Open the file

  if (openedFile == NULL) {
    fprintf(stderr, "TiffWriter: No output file given.\n");
    return false;
  }

159 160 161 162
#ifdef _WIN32
  //Convert C Library handle to Win32 Handle
  priv->f = TIFFFdOpen(_get_osfhandle(fileno(openedFile)), "-", "w");
#else
163
  priv->f = TIFFFdOpen(fileno(openedFile), "-", "w");
164 165
#endif

166

167
  if (!priv->f) {
168 169 170 171 172
    return false;
  }

  // Set TIFF tags

173 174 175 176 177 178 179 180 181 182 183 184 185 186
  TIFFSetField(priv->f, TIFFTAG_IMAGEWIDTH,  width);
  TIFFSetField(priv->f, TIFFTAG_IMAGELENGTH, height);
  TIFFSetField(priv->f, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
  TIFFSetField(priv->f, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
  TIFFSetField(priv->f, TIFFTAG_BITSPERSAMPLE, bitspersample);
  TIFFSetField(priv->f, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  TIFFSetField(priv->f, TIFFTAG_PHOTOMETRIC, photometric);
  TIFFSetField(priv->f, TIFFTAG_COMPRESSION, (uint16) compression);
  TIFFSetField(priv->f, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(priv->f, rowsperstrip));
  TIFFSetField(priv->f, TIFFTAG_XRESOLUTION, (double) hDPI);
  TIFFSetField(priv->f, TIFFTAG_YRESOLUTION, (double) vDPI);
  TIFFSetField(priv->f, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);

  if (priv->format == RGBA_PREMULTIPLIED) {
187
    uint16 extra = EXTRASAMPLE_ASSOCALPHA;
188
    TIFFSetField(priv->f, TIFFTAG_EXTRASAMPLES, 1, &extra);
189 190
  }

191 192 193
  if (priv->format == CMYK) {
    TIFFSetField(priv->f, TIFFTAG_INKSET, INKSET_CMYK);
    TIFFSetField(priv->f, TIFFTAG_NUMBEROFINKS, 4);
194 195
  }

196 197 198 199 200 201 202 203
  return true;
}

bool TiffWriter::writePointers(unsigned char **rowPointers, int rowCount)
{
  // Write all rows to the file

  for (int row = 0; row < rowCount; row++) {
204
    if (TIFFWriteScanline(priv->f, rowPointers[row], row, 0) < 0) {
205 206 207 208 209 210 211 212 213 214 215 216
      fprintf(stderr, "TiffWriter: Error writing tiff row %d\n", row);
      return false;
    }
  }

  return true;
}

bool TiffWriter::writeRow(unsigned char **rowData)
{
  // Add a single row

217 218
  if (TIFFWriteScanline(priv->f, *rowData, priv->curRow, 0) < 0) {
    fprintf(stderr, "TiffWriter: Error writing tiff row %d\n", priv->curRow);
219 220 221
    return false;
  }

222
  priv->curRow++;
223 224 225 226 227 228 229 230

  return true;
}

bool TiffWriter::close()
{
  // Close the file

231
  TIFFClose(priv->f);
232 233 234 235 236

  return true;
}

#endif