/* GEM-View 3.00 SAVING Modul: Bild im Tag-Image-File-Format speichern (c) 22.10.1993 by Dieter Fiebelkorn Grner Weg 29a D-45768 Marl (GERMANY) */ #include #include "image.h" #include "moduls.h" #include "tiff.h" #define Write(a,b,c,d) write(d,c,a) #define SPLIT_STRIP 1 #define TRUE 1 #define FALSE 0 #define INFO1_LEN 14L #define INFO2_LEN 0L #define INFO3_LEN 0L #define INFO1_DEC ((INFO3_LEN ? 0 : 1)) #define INFO2_DEC ((INFO3_LEN ? 0 : 1) + (INFO1_LEN ? 0 : 1)) #define INFO3_DEC ((INFO3_LEN ? 0 : 1) + (INFO1_LEN ? 0 : 1) + (INFO2_LEN ? 0 : 1)) #define OSUBFILETYPE 1 #define IMAGEWIDTH 2 #define IMAGELENGTH 3 #define BITSPERSAMPLE 4 #define PHOTOMETRIC 6 #define IMAGEDESCRIPTION 10 #define STRIPOFFSETS (11 - INFO1_DEC) #define SAMPLESPERPIXEL (13 - INFO1_DEC) #define ROWSPERSTRIP (14 - INFO1_DEC) #define STRIPBYTECOUNTS (15 - INFO1_DEC) #define MINSAMPLEVALUE (16 - INFO1_DEC) #define MAXSAMPLEVALUE (17 - INFO1_DEC) #define PLANARCONFIG (18 - INFO1_DEC) #define SOFTWARE (19 - INFO1_DEC) #define DATETIME (20 - INFO2_DEC) #define COLORMAP (21 - INFO3_DEC) #define NORMAL_TAGS (21 - INFO3_DEC) #define PALETTE_TAGS (22 - INFO3_DEC) #define ADDITIONAL_LEN 14L #define SHIFT_SHORT 16 #define START0 (0) #define PART_0 (STRIPBYTECOUNTS + 1) #define START2 (OSUBFILETYPE) #define PART_2 (PHOTOMETRIC - START2 + 1) #define START3 (STRIPOFFSETS) #define PART_3 (STRIPBYTECOUNTS - START3 + 1) #define SKIPTAGS 4L static TIFFHeader tiffHeader = {TIFF_BIGENDIAN, TIFF_VERSION, 0x00000008L}; static TIFFDirEntry tiffTags[PALETTE_TAGS] = { {TIFFTAG_SUBFILETYPE , TIFF_LONG , 1, 0x00000000L}, {TIFFTAG_OSUBFILETYPE , TIFF_SHORT, 1, 0x00010000L}, {TIFFTAG_IMAGEWIDTH , TIFF_SHORT, 1, 0x00000000L}, /* [ 2] */ {TIFFTAG_IMAGELENGTH , TIFF_SHORT, 1, 0x00000000L}, /* [ 3] */ {TIFFTAG_BITSPERSAMPLE , TIFF_SHORT, 1, 0x00000000L}, /* [ 4] */ {TIFFTAG_COMPRESSION , TIFF_SHORT, 1, 0x00010000L}, {TIFFTAG_PHOTOMETRIC , TIFF_SHORT, 1, 0x00000000L}, /* [ 6] */ {TIFFTAG_THRESHHOLDING , TIFF_SHORT, 1, 0x00010000L}, {TIFFTAG_CELLWIDTH , TIFF_SHORT, 1, 0x00010000L}, {TIFFTAG_CELLLENGTH , TIFF_SHORT, 1, 0x00010000L}, #if INFO3_LEN {TIFFTAG_IMAGEDESCRIPTION, TIFF_ASCII, 0, 0x00000000L}, /* [10] */ #endif {TIFFTAG_STRIPOFFSETS , TIFF_LONG , 1, 0x00000000L}, /* [11] */ {TIFFTAG_ORIENTATION , TIFF_SHORT, 1, 0x00010000L}, {TIFFTAG_SAMPLESPERPIXEL , TIFF_SHORT, 1, 0x00000000L}, /* [13] */ {TIFFTAG_ROWSPERSTRIP , TIFF_LONG , 1, 0x00000000L}, /* [14] */ {TIFFTAG_STRIPBYTECOUNTS , TIFF_LONG , 1, 0x00000000L}, /* [15] */ {TIFFTAG_MINSAMPLEVALUE , TIFF_SHORT, 1, 0x00000000L}, /* [16] */ {TIFFTAG_MAXSAMPLEVALUE , TIFF_SHORT, 1, 0x00000000L}, /* [17] */ {TIFFTAG_PLANARCONFIG , TIFF_SHORT, 1, 0x00010000L}, #if INFO1_LEN {TIFFTAG_SOFTWARE , TIFF_ASCII, 0, 0x00000000L}, /* [18] */ #endif #if INFO2_LEN {TIFFTAG_DATETIME , TIFF_ASCII, 0, 0x00000000L}, /* [19] */ #endif {TIFFTAG_COLORMAP , TIFF_SHORT, 0, 0x00000000L} /* [20] */ }; #if INFO1_LEN static char TIFFInfo1[INFO1_LEN] = "GEM-View 2.30\0"; #endif #if INFO2_LEN static char TIFFInfo2[INFO2_LEN] = "YYYY/MM/DD HH:MM:SS\0"; #endif #if INFO3_LEN static char TIFFInfo3[INFO3_LEN] = "12345678.123\0\0"; #endif void Save_tiff (SAVE_Structure *saveS, unsigned int verbose, unsigned int save_tc, unsigned int packing) { Image *image; char *filename; unsigned int windepth; int fd; char *raster[24]; char *data, out, mask, out_tc; long line, RealLine, plane, w, i; unsigned long offs_software, offs_bpsample, offs_datetime, offs_imagename, offs_colormap, offs_imagedata, stripbytecounts, rowsperstrip, stripsperimage, bitspersample, samplesperpixel, null = 0; short tags, color, colors, count_map, planes; unsigned short width, height, bytes; image = saveS->image; filename = saveS->out_filename; windepth = saveS->screen_depth; if (MONOCHROMEP(image)) { colors = image->rgb.used; if (colors == 1) colors = 2; planes = 1; bitspersample = 1UL; samplesperpixel = 1UL; if (colors == 0) tiffTags[PHOTOMETRIC].tdir_offset = 0L << SHIFT_SHORT; else tiffTags[PHOTOMETRIC].tdir_offset = 3UL << SHIFT_SHORT; tiffTags[SAMPLESPERPIXEL].tdir_offset = samplesperpixel << SHIFT_SHORT; tiffTags[MINSAMPLEVALUE].tdir_offset = 0UL; tiffTags[MAXSAMPLEVALUE].tdir_offset = 1UL << SHIFT_SHORT; } if (PALETTEP(image) && !save_tc) { planes = image->depth; if (planes <= 1) planes = 1; if (planes > 1 && planes <= 2) planes = 2; if (planes > 2 && planes <= 4) planes = 4; if (planes > 4 && planes <= 8) planes = 8; if (packing) bitspersample = (unsigned long)planes; else bitspersample = (unsigned long)(planes = 8); samplesperpixel = 1UL; colors = 1UL << bitspersample; tiffTags[PHOTOMETRIC].tdir_offset = 3UL << SHIFT_SHORT; tiffTags[SAMPLESPERPIXEL].tdir_offset = samplesperpixel << SHIFT_SHORT; tiffTags[MINSAMPLEVALUE].tdir_offset = 0UL; tiffTags[MAXSAMPLEVALUE].tdir_offset = (long)(colors - 1) << SHIFT_SHORT; } if (TRUECOLORP(image) || save_tc) { colors = 0; planes = 24; bitspersample = 8UL; samplesperpixel = 3UL; tiffTags[PHOTOMETRIC].tdir_offset = 2UL << SHIFT_SHORT; tiffTags[SAMPLESPERPIXEL].tdir_offset = samplesperpixel << SHIFT_SHORT; } if (colors == 0) tags = NORMAL_TAGS; else tags = PALETTE_TAGS; #if !SPLIT_STRIP if (!split_strip) tags -= SKIPTAGS; #endif if (TRUECOLORP(image) || save_tc) tags -= 2; count_map = 3 * colors; offs_software = ADDITIONAL_LEN + tags * sizeof(TIFFDirEntry); offs_bpsample = offs_software + INFO1_LEN; offs_datetime = offs_bpsample; if (samplesperpixel == 3UL) offs_datetime += 4 * sizeof(short); else offs_bpsample = bitspersample << SHIFT_SHORT; offs_imagename= offs_datetime + INFO2_LEN; offs_colormap = offs_imagename+ INFO3_LEN; offs_imagedata= offs_colormap + sizeof(short) * count_map; if (image->unalignwidth != 0) width = image->unalignwidth; else width = image->width; if (samplesperpixel * bitspersample == 1) width = 16L * (width / 16L + (width % 16L ? 1 : 0)); if (samplesperpixel * bitspersample == 2) width = 8L * (width / 8L + (width % 8L ? 1 : 0)); if (samplesperpixel * bitspersample == 4) width = 4L * (width / 4L + (width % 4L ? 1 : 0)); if (samplesperpixel * bitspersample == 8) width = 2L * (width / 2L + (width % 2L ? 1 : 0)); height = image->height; #if INFO1_LEN tiffTags[SOFTWARE].tdir_count = INFO1_LEN; tiffTags[SOFTWARE].tdir_offset = offs_software; #endif #if INFO2_LEN tiffTags[DATETIME].tdir_count = INFO2_LEN; tiffTags[DATETIME].tdir_offset = offs_datetime; #endif #if INFO3_LEN tiffTags[IMAGEDESCRIPTION].tdir_count = INFO3_LEN; tiffTags[IMAGEDESCRIPTION].tdir_offset = offs_imagename; #endif tiffTags[IMAGEWIDTH].tdir_offset = (long)width << SHIFT_SHORT; tiffTags[IMAGELENGTH].tdir_offset = (long)height << SHIFT_SHORT; tiffTags[BITSPERSAMPLE].tdir_count = samplesperpixel; tiffTags[BITSPERSAMPLE].tdir_offset = offs_bpsample; tiffTags[COLORMAP].tdir_count = count_map; tiffTags[COLORMAP].tdir_offset = offs_colormap; stripbytecounts = (long)width * height * samplesperpixel * bitspersample / 8L; #if !SPLIT_STRIP if (!split_strip || stripbytecounts < 8192L) { #else if (stripbytecounts < 8192L) { #endif rowsperstrip = 0xFFFFFFFFL; stripsperimage = 1L; tiffTags[STRIPBYTECOUNTS].tdir_type = TIFF_LONG; } else { rowsperstrip = 8192L / ((long)width * samplesperpixel * bitspersample / 8L); stripsperimage = ((long)height + rowsperstrip - 1) / rowsperstrip; if (stripsperimage > 2) { stripbytecounts = offs_imagedata; offs_imagedata += stripsperimage * sizeof(short); } else { bytes = (int)(rowsperstrip * width * samplesperpixel * bitspersample / 8L); null = (unsigned long)bytes << 16; stripbytecounts = (long)width * height * samplesperpixel * bitspersample / 8L; bytes = (int)(stripbytecounts - ((stripsperimage - 1L) * bytes)); null |= bytes; stripbytecounts = null; } tiffTags[STRIPBYTECOUNTS].tdir_type = TIFF_SHORT; } tiffTags[ROWSPERSTRIP].tdir_offset = rowsperstrip; tiffTags[STRIPBYTECOUNTS].tdir_count = stripsperimage; tiffTags[STRIPBYTECOUNTS].tdir_offset = stripbytecounts; tiffTags[STRIPOFFSETS].tdir_count = stripsperimage; tiffTags[STRIPOFFSETS].tdir_offset = offs_imagedata; saveS->print.printout (" Saving TIFF Image '%s' ... ", filename); if ((fd = saveS->output.open(filename)) > 0) { if (saveS->output.Write(&tiffHeader, 1L, sizeof(TIFFHeader), fd) != sizeof(TIFFHeader)) goto CloseAndRemove; if (saveS->output.Write(&tags, 1L, sizeof(short), fd) != sizeof(short)) goto CloseAndRemove; #if !SPLIT_STRIP if (split_strip) { #endif if (saveS->output.Write(&tiffTags[START0], 1L, sizeof(TIFFDirEntry) * PART_0, fd) != sizeof(TIFFDirEntry) * PART_0) goto CloseAndRemove; #if !SPLIT_STRIP } else { if (saveS->output.Write(&tiffTags[START2], 1L, sizeof(TIFFDirEntry) * PART_2, fd) != sizeof(TIFFDirEntry) * PART_2) goto CloseAndRemove; #if INFO3_LEN if (saveS->output.Write(&tiffTags[IMAGEDESCRIPTION], 1L, sizeof(TIFFDirEntry), fd) != sizeof(TIFFDirEntry)) goto CloseAndRemove; #endif if (saveS->output.Write(&tiffTags[START3], 1L, sizeof(TIFFDirEntry) * PART_3, fd) != sizeof(TIFFDirEntry) * PART_3) goto CloseAndRemove; } #endif if (!(TRUECOLORP(image) || save_tc)) { if (saveS->output.Write(&tiffTags[MINSAMPLEVALUE], 1L, sizeof(TIFFDirEntry), fd) != sizeof(TIFFDirEntry)) goto CloseAndRemove; if (saveS->output.Write(&tiffTags[MAXSAMPLEVALUE], 1L, sizeof(TIFFDirEntry), fd) != sizeof(TIFFDirEntry)) goto CloseAndRemove; } if (saveS->output.Write(&tiffTags[PLANARCONFIG], 1L, sizeof(TIFFDirEntry), fd) != sizeof(TIFFDirEntry)) goto CloseAndRemove; #if INFO1_LEN if (saveS->output.Write(&tiffTags[SOFTWARE], 1L, sizeof(TIFFDirEntry), fd) != sizeof(TIFFDirEntry)) goto CloseAndRemove; #endif #if INFO2_LEN if (saveS->output.Write(&tiffTags[DATETIME], 1L, sizeof(TIFFDirEntry), fd) != sizeof(TIFFDirEntry)) goto CloseAndRemove; #endif if (colors != 0) if (saveS->output.Write(&tiffTags[COLORMAP], 1L, sizeof(TIFFDirEntry), fd) != sizeof(TIFFDirEntry)) goto CloseAndRemove; null = 0L; if (saveS->output.Write(&null, 1L, sizeof(long), fd) != sizeof(long)) goto CloseAndRemove; #if INFO1_LEN if (saveS->output.Write(TIFFInfo1, 1L, INFO1_LEN, fd) != INFO1_LEN) goto CloseAndRemove; #endif if (samplesperpixel == 3UL) { null = 0x00080008L; if (saveS->output.Write(&null, 1L, sizeof(long), fd) != sizeof(long)) goto CloseAndRemove; null = 0x00080000L; if (saveS->output.Write(&null, 1L, sizeof(long), fd) != sizeof(long)) goto CloseAndRemove; } #if INFO2_LEN if (saveS->output.Write(TIFFInfo2, 1L, INFO2_LEN, fd) != INFO2_LEN) goto CloseAndRemove; #endif #if INFO3_LEN if (saveS->output.Write(TIFFInfo3, 1L, INFO3_LEN, fd) != INFO3_LEN) goto CloseAndRemove; #endif null = 0; for (color = 0; color < colors; color++) { if (color < image->rgb.used) { if (saveS->output.Write(&image->rgb.red[color], 1L, sizeof(short), fd) != sizeof(short)) goto CloseAndRemove; } else { if (saveS->output.Write(&null, 1L, sizeof(short), fd) != sizeof(short)) goto CloseAndRemove; } } for (color = 0; color < colors; color++) { if (color < image->rgb.used) { if (saveS->output.Write(&image->rgb.green[color], 1L, sizeof(short), fd) != sizeof(short)) goto CloseAndRemove; } else { if (saveS->output.Write(&null, 1L, sizeof(short), fd) != sizeof(short)) goto CloseAndRemove; } } for (color = 0; color < colors; color++) { if (color < image->rgb.used) { if (saveS->output.Write(&image->rgb.blue[color], 1L, sizeof(short), fd) != sizeof(short)) goto CloseAndRemove; } else { if (saveS->output.Write(&null, 1L, sizeof(short), fd) != sizeof(short)) goto CloseAndRemove; } } if (stripsperimage > 2) { bytes = (int)(rowsperstrip * width * samplesperpixel * bitspersample / 8L); for (null = 1; null < stripsperimage; null++) { if (saveS->output.Write(&bytes, 1L, sizeof(short), fd) != sizeof(short)) goto CloseAndRemove; } stripbytecounts = (long)width * height * samplesperpixel * bitspersample / 8L; bytes = (int)(stripbytecounts - ((stripsperimage - 1L) * bytes)); if (saveS->output.Write(&bytes, 1L, sizeof(short), fd) != sizeof(short)) goto CloseAndRemove; } if (stripsperimage > 1) { offs_imagedata += stripsperimage * sizeof(long); bytes = (int)(rowsperstrip * width * samplesperpixel * bitspersample / 8L); for (null = 0; null < stripsperimage; null++) { if (saveS->output.Write(&offs_imagedata, 1L, sizeof(long), fd) != sizeof(long)) goto CloseAndRemove; offs_imagedata += bytes; } } if (MONOCHROMEP(image)) { RealLine = (image->width >> 4) + ((image->width & 0x000F) ? 1 : 0); RealLine += RealLine; for (line = 0; line < image->height; line++) { raster[0] = image->data + ((long)line * RealLine); if (saveS->output.Write(raster[0], 1L, width / 8, fd) != width / 8) goto CloseAndRemove; } } if (ATARI_RGBP(image)) { RealLine = (image->width >> 4) + ((image->width & 0x000F) ? 1 : 0); RealLine += RealLine; for (line = 0; line < image->height; line++) { raster[0] = image->data + ((long)line * RealLine); for (plane = 1; plane < image->depth; plane++) raster[plane] = raster[plane-1] + (long)RealLine * height; switch ((int)bitspersample | (save_tc ? 0x80 : 0x00)) { case 2: mask = 0x80; for (i = 0, w = 0; w < width; w+=4) { out = 0; for (plane = 0; plane < image->depth; plane++) { if (raster[plane][i] & mask) out |= (1U << plane); } out <<= 2; mask >>= 1; for (plane = 0; plane < image->depth; plane++) { if (raster[plane][i] & mask) out |= (1U << plane); } out <<= 2; mask >>= 1; for (plane = 0; plane < image->depth; plane++) { if (raster[plane][i] & mask) out |= (1U << plane); } out <<= 2; mask >>= 1; for (plane = 0; plane < image->depth; plane++) { if (raster[plane][i] & mask) out |= (1U << plane); } mask >>= 1; if (saveS->output.Write(&out, 1L, 1L, fd) != 1L) goto CloseAndRemove; if (mask == 0) { mask = 0x80; i++; } } break; case 4: mask = 0x80; for (i = 0, w = 0; w < width; w += 2) { out = 0; for (plane = 0; plane < image->depth; plane++) { if (raster[plane][i] & mask) out |= (1U << plane); } out <<= 4; mask >>= 1; for (plane = 0; plane < image->depth; plane++) { if (raster[plane][i] & mask) out |= (1U << plane); } mask >>= 1; if (saveS->output.Write(&out, 1L, 1L, fd) != 1L) goto CloseAndRemove; if (mask == 0) { mask = 0x80; i++; } } break; case 8: mask = 0x80; for (i = 0, w = 0; w < width; w++) { out = 0; for (plane = 0; plane < image->depth; plane++) { if (raster[plane][i] & mask) out |= (1U << plane); } mask >>= 1; if (saveS->output.Write(&out, 1L, 1L, fd) != 1L) goto CloseAndRemove; if (mask == 0) { mask = 0x80; i++; } } break; case 0x82: case 0x84: case 0x88: mask = 0x80; for (i = 0, w = 0; w < width; w++) { out = 0; for (plane = 0; plane < image->depth; plane++) { if (raster[plane][i] & mask) out |= (1U << plane); } mask >>= 1; out_tc = (char)(image->rgb.red[out] >> 8); if (saveS->output.Write(&out_tc, 1L, 1L, fd) != 1L) goto CloseAndRemove; out_tc = (char)(image->rgb.green[out] >> 8); if (saveS->output.Write(&out_tc, 1L, 1L, fd) != 1L) goto CloseAndRemove; out_tc = (char)(image->rgb.blue[out] >> 8); if (saveS->output.Write(&out_tc, 1L, 1L, fd) != 1L) goto CloseAndRemove; if (mask == 0) { mask = 0x80; i++; } } break; } } } if (RGBP(image)) { RealLine = (image->width >> 4) + ((image->width & 0x000F) ? 1 : 0); RealLine <<= 4; for (line = 0; line < image->height; line++) { raster[0] = image->data + ((long)line * RealLine); switch ((int)bitspersample | (save_tc ? 0x80 : 0x00)) { case 1: case 0x81: data = raster[0]; for (w = 0; w < width; w += 8) { out = *data++ << 7; out |= *data++ << 6; out |= *data++ << 5; out |= *data++ << 4; out |= *data++ << 3; out |= *data++ << 2; out |= *data++ << 1; out |= *data++; if (saveS->output.Write(&out, 1L, 1L, fd) != 1L) goto CloseAndRemove; } break; case 2: data = raster[0]; for (w = 0; w < width; w += 4) { out = *data++ << 6; out |= *data++ << 4; out |= *data++ << 2; out |= *data++; if (saveS->output.Write(&out, 1L, 1L, fd) != 1L) goto CloseAndRemove; } break; case 4: data = raster[0]; for (w = 0; w < width; w += 2) { out = *data++ << 4; out |= *data++; if (saveS->output.Write(&out, 1L, 1L, fd) != 1L) goto CloseAndRemove; } break; case 8: if (saveS->output.Write(raster[0], 1L, width, fd) != width) goto CloseAndRemove; break; case 0x82: case 0x84: case 0x88: data = raster[0]; for (w = 0; w < width; w++) { out_tc = (char)(image->rgb.red[*data] >> 8); if (saveS->output.Write(&out_tc, 1L, 1L, fd) != 1L) goto CloseAndRemove; out_tc = (char)(image->rgb.green[*data] >> 8); if (saveS->output.Write(&out_tc, 1L, 1L, fd) != 1L) goto CloseAndRemove; out_tc = (char)(image->rgb.blue[*data] >> 8); if (saveS->output.Write(&out_tc, 1L, 1L, fd) != 1L) goto CloseAndRemove; data++; } break; } } } if (TRUECOLORP(image)) { RealLine = (image->width >> 4) + ((image->width & 0x000F) ? 1 : 0); RealLine <<= 4; RealLine = 3 * RealLine; for (line = 0; line < image->height; line++) { raster[0] = image->data + ((long)line * RealLine); data = raster[0]; if (saveS->output.Write(data, 1L, 3L * width, fd) != 3L * width) goto CloseAndRemove; } } if (saveS->output.close(fd) != 0) { fd = 0; goto CloseAndRemove; } saveS->print.printout ("done.\n"); return; } CloseAndRemove: saveS->events.alert(1, "[3][ | Error in writing! | | Disk full ? ][ OK ]"); if (fd > 0) saveS->output.close(fd); saveS->output.delete(filename); saveS->print.printout ("error.\n"); return; } void Save_tiff1(SAVE_Structure *saveS, unsigned int verbose) { Save_tiff(saveS, verbose, FALSE, TRUE); }