initial commit
[goodguy/history.git] / cinelerra-5.0 / cinelerra / filetiff.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "asset.h"
23 #include "edit.h"
24 #include "file.h"
25 #include "filetiff.h"
26 #include "language.h"
27 #include "vframe.h"
28 #include "mainerror.h"
29
30 #include <stdint.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 FileTIFF::FileTIFF(Asset *asset, File *file)
35  : FileList(asset, file, "TIFFLIST", ".tif", FILE_TIFF, FILE_TIFF_LIST)
36 {
37         asset->video_data = 1;
38         temp = 0;
39 }
40
41 FileTIFF::~FileTIFF()
42 {
43         if(temp) delete temp;
44 }
45
46
47 void FileTIFF::get_parameters(BC_WindowBase *parent_window,
48         Asset *asset,
49         BC_WindowBase* &format_window,
50         int audio_options,
51         int video_options)
52 {
53         if(video_options)
54         {
55                 TIFFConfigVideo *window = new TIFFConfigVideo(parent_window, asset);
56                 format_window = window;
57                 window->create_objects();
58                 window->run_window();
59                 delete window;
60         }
61 }
62
63
64 int FileTIFF::check_sig(Asset *asset)
65 {
66         FILE *stream = fopen(asset->path, "rb");
67
68         if(stream)
69         {
70                 char test[10];
71                 (void)fread(test, 10, 1, stream);
72                 fclose(stream);
73
74                 if(test[0] == 'I' && test[1] == 'I')
75                 {
76                         return 1;
77                 }
78                 else
79                 if(test[0] == 'T' && test[1] == 'I' && test[2] == 'F' && test[3] == 'F' &&
80                         test[4] == 'L' && test[5] == 'I' && test[6] == 'S' && test[7] == 'T')
81                 {
82                         return 1;
83                 }
84                 else
85                 if(strlen(asset->path) > 4 &&
86                         !strcasecmp(asset->path + strlen(asset->path) - 4, ".tif"))
87                 {
88                         return 1;
89                 }
90                 else
91                 if(strlen(asset->path) > 5 &&
92                         !strcasecmp(asset->path + strlen(asset->path) - 5, ".tiff"))
93                 {
94                         return 1;
95                 }
96         }
97         return 0;
98 }
99
100 const char* FileTIFF::compression_to_str(int value)
101 {
102         switch(value)
103         {
104                 case FileTIFF::NONE: return "None"; break;
105                 case FileTIFF::LZW: return "LZW"; break;
106                 case FileTIFF::PACK_BITS: return "Pack Bits"; break;
107                 case FileTIFF::DEFLATE: return "Deflate"; break;
108                 case FileTIFF::JPEG: return "JPEG"; break;
109                 default:
110                         return "None";
111                         break;
112         }
113 }
114
115 const char* FileTIFF::cmodel_to_str(int value)
116 {
117         switch(value)
118         {
119                 case FileTIFF::GREYSCALE: return "Greyscale"; break;
120                 case FileTIFF::RGB_888: return "RGB-8 Bit"; break;
121                 case FileTIFF::RGB_161616: return "RGB-16 Bit"; break;
122                 case FileTIFF::RGBA_8888: return "RGBA-8 Bit"; break;
123                 case FileTIFF::RGBA_16161616: return "RGBA-16 Bit"; break;
124                 case FileTIFF::RGB_FLOAT: return "RGB-FLOAT"; break;
125                 case FileTIFF::RGBA_FLOAT: return "RGBA-FLOAT"; break;
126                 default:
127                         return "RGB-8 Bit";
128                         break;
129         }
130 }
131
132
133 int FileTIFF::can_copy_from(Asset *asset, int64_t position)
134 {
135         if(asset->format == FILE_TIFF_LIST ||
136                 asset->format == FILE_TIFF)
137                 return 1;
138
139         return 0;
140 }
141
142
143
144 int FileTIFF::read_frame_header(char *path)
145 {
146         TIFF *stream;
147         int result = 0;
148
149         if(!(stream = TIFFOpen(path, "rb")))
150         {
151                 eprintf("Error while opening \"%s\" for reading. \n%m\n", asset->path);
152                 return 1;
153         }
154
155         char *ptr = 0;
156         TIFFGetField(stream, TIFFTAG_MODEL, &ptr);
157 //printf("FileTIFF::read_frame_header 1 %s\n", ptr);
158         if(ptr && !strcmp(ptr, "Canon EOS-1DS"))       // FIXME: Does this have a purpose?
159         {
160                 printf("FileTIFF::read_frame_header: got a %s.\n",
161                         ptr);
162         }
163
164 // The raw format for certain cameras deviates from TIFF here.
165
166         TIFFGetField(stream, TIFFTAG_IMAGEWIDTH, &(asset->width));
167         TIFFGetField(stream, TIFFTAG_IMAGELENGTH, &(asset->height));
168
169         int components = 0;
170         TIFFGetField(stream, TIFFTAG_SAMPLESPERPIXEL, &components);
171         int bitspersample = 0;
172         TIFFGetField(stream, TIFFTAG_BITSPERSAMPLE, &bitspersample);
173         int sampleformat = 0;
174         TIFFGetField(stream, TIFFTAG_SAMPLEFORMAT, &sampleformat);
175
176         if(bitspersample == 8 && components == 3)
177                 asset->tiff_cmodel = FileTIFF::RGB_888;
178         else
179         if(bitspersample == 16 && components == 3)
180                 asset->tiff_cmodel = FileTIFF::RGB_161616;
181         else
182         if(bitspersample == 8 && components == 4)
183                 asset->tiff_cmodel = FileTIFF::RGBA_8888;
184         else
185         if(bitspersample == 16 && components == 4)
186                 asset->tiff_cmodel = FileTIFF::RGBA_16161616;
187         else
188         if(bitspersample == 32 && components == 3)
189                 asset->tiff_cmodel = FileTIFF::RGB_FLOAT;
190         else
191         if(bitspersample == 32 && components == 4)
192                 asset->tiff_cmodel = FileTIFF::RGBA_FLOAT;
193         else
194         if(bitspersample == 8 && (components == 1 || components == 0))
195                 asset->tiff_cmodel = FileTIFF::GREYSCALE;
196
197 //printf("FileTIFF::read_frame_header %d %d %d\n", bitspersample, components, asset->tiff_cmodel);
198         TIFFClose(stream);
199
200         return result;
201 }
202
203 int FileTIFF::colormodel_supported(int colormodel)
204 {
205         switch(asset->tiff_cmodel)
206         {
207                 case FileTIFF::RGB_888: return BC_RGB888; break;
208                 case FileTIFF::RGB_161616: return BC_RGB_FLOAT; break;
209                 case FileTIFF::GREYSCALE: return BC_RGB888; break;
210                 case FileTIFF::RGBA_8888: return BC_RGBA8888; break;
211                 case FileTIFF::RGBA_16161616: return BC_RGBA_FLOAT; break;
212                 case FileTIFF::RGB_FLOAT: return BC_RGB_FLOAT; break;
213                 case FileTIFF::RGBA_FLOAT: return BC_RGBA_FLOAT; break;
214                 default: return BC_RGB888; break;
215         }
216 }
217
218 int FileTIFF::get_best_colormodel(Asset *asset, int driver)
219 {
220         switch(asset->tiff_cmodel)
221         {
222                 case FileTIFF::GREYSCALE: return BC_RGB888; break;
223                 case FileTIFF::RGB_888: return BC_RGB888; break;
224                 case FileTIFF::RGB_161616: return BC_RGB_FLOAT; break;
225                 case FileTIFF::RGBA_8888: return BC_RGBA8888; break;
226                 case FileTIFF::RGBA_16161616: return BC_RGBA_FLOAT; break;
227                 case FileTIFF::RGB_FLOAT: return BC_RGB_FLOAT; break;
228                 case FileTIFF::RGBA_FLOAT: return BC_RGBA_FLOAT; break;
229                 default: return BC_RGB888; break;
230         }
231 }
232
233
234 static tsize_t tiff_read(thandle_t ptr, tdata_t buf, tsize_t size)
235 {
236         FileTIFFUnit *tiff_unit = (FileTIFFUnit*)ptr;
237         if(tiff_unit->data->get_compressed_size() < tiff_unit->offset + size)
238                 return 0;
239         memcpy(buf, tiff_unit->data->get_data() + tiff_unit->offset, size);
240         tiff_unit->offset += size;
241         return size;
242 }
243
244 static tsize_t tiff_write(thandle_t ptr, tdata_t buf, tsize_t size)
245 {
246         FileTIFFUnit *tiff_unit = (FileTIFFUnit*)ptr;
247         if(tiff_unit->data->get_compressed_allocated() < tiff_unit->offset + size)
248         {
249                 tiff_unit->data->allocate_compressed_data((tiff_unit->offset + size) * 2);
250         }
251
252
253         if(tiff_unit->data->get_compressed_size() < tiff_unit->offset + size)
254                 tiff_unit->data->set_compressed_size(tiff_unit->offset + size);
255         memcpy(tiff_unit->data->get_data() + tiff_unit->offset,
256                 buf,
257                 size);
258         tiff_unit->offset += size;
259         return size;
260 }
261
262 static toff_t tiff_seek(thandle_t ptr, toff_t off, int whence)
263 {
264         FileTIFFUnit *tiff_unit = (FileTIFFUnit*)ptr;
265         switch(whence)
266         {
267                 case SEEK_SET:
268                         tiff_unit->offset = off;
269                         break;
270                 case SEEK_CUR:
271                         tiff_unit->offset += off;
272                         break;
273                 case SEEK_END:
274                         tiff_unit->offset = tiff_unit->data->get_compressed_size() + off;
275                         break;
276         }
277         return tiff_unit->offset;
278 }
279
280 static int tiff_close(thandle_t ptr)
281 {
282         return 0;
283 }
284
285 static toff_t tiff_size(thandle_t ptr)
286 {
287         FileTIFFUnit *tiff_unit = (FileTIFFUnit*)ptr;
288         return tiff_unit->data->get_compressed_size();
289 }
290
291 static int tiff_mmap(thandle_t ptr, tdata_t* pbase, toff_t* psize)
292 {
293         FileTIFFUnit *tiff_unit = (FileTIFFUnit*)ptr;
294         *pbase = tiff_unit->data->get_data();
295         *psize = tiff_unit->data->get_compressed_size();
296         return 0;
297 }
298
299 void tiff_unmap(thandle_t ptr, tdata_t base, toff_t size)
300 {
301 }
302
303 int FileTIFF::read_frame(VFrame *output, VFrame *input)
304 {
305         FileTIFFUnit *unit = new FileTIFFUnit(this, 0);
306         TIFF *stream;
307         unit->offset = 0;
308         unit->data = input;
309
310         stream = TIFFClientOpen("FileTIFF",
311                 "r",
312             (void*)unit,
313             tiff_read,
314                 tiff_write,
315             tiff_seek,
316                 tiff_close,
317             tiff_size,
318             tiff_mmap,
319                 tiff_unmap);
320
321 // This loads the original TIFF data into each scanline of the output frame,
322 // assuming the output scanlines are bigger than the input scanlines.
323 // Then it expands the input data in reverse to fill the row.
324         for(int i = 0; i < asset->height; i++)
325         {
326                 TIFFReadScanline(stream, output->get_rows()[i], i, 0);
327
328 // For the greyscale model, the output is RGB888 but the input must be expanded
329                 if(asset->tiff_cmodel == FileTIFF::GREYSCALE)
330                 {
331                         unsigned char *row = output->get_rows()[i];
332                         for(int j = output->get_w() - 1; j >= 0; j--)
333                         {
334                                 unsigned char value = row[j];
335                                 row[j * 3] = value;
336                                 row[j * 3 + 1] = value;
337                                 row[j * 3 + 2] = value;
338                         }
339                 }
340 // For the 16 bit models, the output is floating point.
341                 else
342                 if(asset->tiff_cmodel == FileTIFF::RGB_161616)
343                 {
344                         uint16_t *input_row = (uint16_t*)output->get_rows()[i];
345                         float *output_row = (float*)output->get_rows()[i];
346                         for(int j = output->get_w() - 1; j >= 0; j--)
347                         {
348                                 uint16_t r = input_row[j * 3];
349                                 uint16_t g = input_row[j * 3 + 1];
350                                 uint16_t b = input_row[j * 3 + 2];
351                                 output_row[j * 3] = (float)r / 65535;
352                                 output_row[j * 3 + 1] = (float)g / 65535;
353                                 output_row[j * 3 + 2] = (float)b / 65535;
354                         }
355                 }
356                 else
357                 if(asset->tiff_cmodel == FileTIFF::RGBA_16161616)
358                 {
359                         uint16_t *input_row = (uint16_t*)output->get_rows()[i];
360                         float *output_row = (float*)output->get_rows()[i];
361                         for(int j = output->get_w() - 1; j >= 0; j--)
362                         {
363                                 uint16_t r = input_row[j * 4];
364                                 uint16_t g = input_row[j * 4 + 1];
365                                 uint16_t b = input_row[j * 4 + 2];
366                                 output_row[j * 4] = (float)r / 65535;
367                                 output_row[j * 4 + 1] = (float)g / 65535;
368                                 output_row[j * 4 + 2] = (float)b / 65535;
369                         }
370                 }
371         }
372
373         TIFFClose(stream);
374         delete unit;
375
376         return 0;
377 }
378
379 int FileTIFF::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
380 {
381 //printf("FileTIFF::write_frame 1\n");
382         FileTIFFUnit *tiff_unit = (FileTIFFUnit*)unit;
383         int result = 0;
384         TIFF *stream;
385         tiff_unit->offset = 0;
386         tiff_unit->data = data;
387         tiff_unit->data->set_compressed_size(0);
388
389         stream = TIFFClientOpen("FileTIFF",
390                 "w",
391             (void*)tiff_unit,
392             tiff_read,
393                 tiff_write,
394             tiff_seek,
395                 tiff_close,
396             tiff_size,
397             tiff_mmap,
398                 tiff_unmap);
399
400         int components, color_model, bits, compression;
401         int sampleformat = SAMPLEFORMAT_UINT;
402         //int bytesperrow, type;
403         switch(asset->tiff_cmodel)
404         {
405                 case FileTIFF::RGB_888:
406                         components = 3;
407                         color_model = BC_RGB888;
408                         bits = 8;
409                         //type = TIFF_BYTE;
410                         //bytesperrow = 3 * asset->width;
411                         break;
412                 case FileTIFF::RGB_161616:
413                         components = 3;
414                         color_model = BC_RGB_FLOAT;
415                         bits = 16;
416                         //type = TIFF_SHORT;
417                         //bytesperrow = 6 * asset->width;
418                         break;
419                 case FileTIFF::RGBA_8888:
420                         components = 4;
421                         color_model = BC_RGBA8888;
422                         bits = 8;
423                         //type = TIFF_BYTE;
424                         //bytesperrow = 4 * asset->width;
425                         break;
426                 case FileTIFF::RGBA_16161616:
427                         components = 4;
428                         color_model = BC_RGBA_FLOAT;
429                         bits = 16;
430                         //type = TIFF_SHORT;
431                         //bytesperrow = 8 * asset->width;
432                         break;
433                 case FileTIFF::RGB_FLOAT:
434                         components = 3;
435                         color_model = BC_RGB_FLOAT;
436                         bits = 32;
437                         //type = TIFF_FLOAT;
438                         sampleformat = SAMPLEFORMAT_IEEEFP;
439                         //bytesperrow = 12 * asset->width;
440                         break;
441                 case FileTIFF::RGBA_FLOAT:
442                         components = 4;
443                         color_model = BC_RGBA_FLOAT;
444                         bits = 32;
445                         //type = TIFF_FLOAT;
446                         sampleformat = SAMPLEFORMAT_IEEEFP;
447                         //bytesperrow = 16 * asset->width;
448                         break;
449                 default:
450                         components = 3;
451                         color_model = BC_RGB888;
452                         bits = 8;
453                         //type = TIFF_BYTE;
454                         //bytesperrow = 3 * asset->width;
455                         break;
456         }
457
458
459         switch(asset->tiff_compression)
460         {
461                 case FileTIFF::LZW:
462                         compression = COMPRESSION_LZW;
463                         break;
464                 case FileTIFF::PACK_BITS:
465                         compression = COMPRESSION_PACKBITS;
466                         break;
467                 case FileTIFF::DEFLATE:
468                         compression = COMPRESSION_DEFLATE;
469                         break;
470                 case FileTIFF::JPEG:
471                         compression = COMPRESSION_JPEG;
472                         break;
473                 default:
474                         compression = COMPRESSION_NONE;
475                         break;
476         }
477
478         TIFFSetField(stream, TIFFTAG_IMAGEWIDTH, asset->width);
479         TIFFSetField(stream, TIFFTAG_IMAGELENGTH, asset->height);
480         TIFFSetField(stream, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
481         TIFFSetField(stream, TIFFTAG_SAMPLESPERPIXEL, components);
482         TIFFSetField(stream, TIFFTAG_BITSPERSAMPLE, bits);
483     TIFFSetField(stream, TIFFTAG_SAMPLEFORMAT, sampleformat);
484         TIFFSetField(stream, TIFFTAG_COMPRESSION, compression);
485         TIFFSetField(stream, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
486         TIFFSetField(stream, TIFFTAG_ROWSPERSTRIP,
487                 TIFFDefaultStripSize(stream, (uint32_t)-1));
488 //      TIFFSetField(stream, TIFFTAG_ROWSPERSTRIP,
489 //              (8 * 1024) / bytesperrow);
490         TIFFSetField(stream, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
491
492         if(frame->get_color_model() == color_model)
493         {
494                 for(int i = 0; i < asset->height; i++)
495                 {
496                         TIFFWriteScanline(stream, frame->get_rows()[i], i, 0);
497                 }
498         }
499         else
500         {
501                 if(tiff_unit->temp &&
502                         tiff_unit->temp->get_color_model() != color_model)
503                 {
504                         delete tiff_unit->temp;
505                         tiff_unit->temp = 0;
506                 }
507                 if(!tiff_unit->temp)
508                 {
509                         tiff_unit->temp = new VFrame(0,
510                                 -1,
511                                 asset->width,
512                                 asset->height,
513                                 color_model,
514                                 -1);
515                 }
516
517                 BC_CModels::transfer(tiff_unit->temp->get_rows(),
518                         frame->get_rows(),
519                         tiff_unit->temp->get_y(),
520                         tiff_unit->temp->get_u(),
521                         tiff_unit->temp->get_v(),
522                         frame->get_y(),
523                         frame->get_u(),
524                         frame->get_v(),
525                         0,
526                         0,
527                         frame->get_w(),
528                         frame->get_h(),
529                         0,
530                         0,
531                         frame->get_w(),
532                         frame->get_h(),
533                         frame->get_color_model(),
534                         color_model,
535                         0,
536                         frame->get_w(),
537                         frame->get_w());
538                 for(int i = 0; i < asset->height; i++)
539                 {
540                         TIFFWriteScanline(stream, tiff_unit->temp->get_rows()[i], i, 0);
541                 }
542         }
543
544         TIFFClose(stream);
545
546 //printf("FileTIFF::write_frame 10\n");
547         return result;
548 }
549
550 FrameWriterUnit* FileTIFF::new_writer_unit(FrameWriter *writer)
551 {
552         return new FileTIFFUnit(this, writer);
553 }
554
555
556
557
558
559
560
561
562 FileTIFFUnit::FileTIFFUnit(FileTIFF *file, FrameWriter *writer)
563  : FrameWriterUnit(writer)
564 {
565         this->file = file;
566         temp = 0;
567 }
568
569 FileTIFFUnit::~FileTIFFUnit()
570 {
571         if(temp) delete temp;
572 }
573
574
575
576
577
578
579
580
581
582
583
584
585 TIFFConfigVideo::TIFFConfigVideo(BC_WindowBase *parent_window, Asset *asset)
586  : BC_Window(PROGRAM_NAME ": Video Compression",
587         parent_window->get_abs_cursor_x(1),
588         parent_window->get_abs_cursor_y(1),
589         400,
590         200)
591 {
592         this->parent_window = parent_window;
593         this->asset = asset;
594 }
595
596 TIFFConfigVideo::~TIFFConfigVideo()
597 {
598 }
599
600 void TIFFConfigVideo::create_objects()
601 {
602         lock_window("TIFFConfigVideo::create_objects()");
603         int x = 10, y = 10;
604
605         add_subwindow(new BC_Title(x, y, "Colorspace:"));
606         TIFFColorspace *menu1;
607         add_subwindow(menu1 = new TIFFColorspace(this, x + 150, y, 200));
608         menu1->create_objects();
609         y += 40;
610         add_subwindow(new BC_Title(x, y, "Compression:"));
611         TIFFCompression *menu2;
612         add_subwindow(menu2 = new TIFFCompression(this, x + 150, y, 200));
613         menu2->create_objects();
614
615         add_subwindow(new BC_OKButton(this));
616         show_window(1);
617         unlock_window();
618 }
619
620 int TIFFConfigVideo::close_event()
621 {
622         set_done(0);
623         return 1;
624 }
625
626
627
628
629
630
631 TIFFColorspace::TIFFColorspace(TIFFConfigVideo *gui, int x, int y, int w)
632  : BC_PopupMenu(x,
633         y,
634         w,
635         FileTIFF::cmodel_to_str(gui->asset->tiff_cmodel))
636 {
637         this->gui = gui;
638 }
639 int TIFFColorspace::handle_event()
640 {
641         return 1;
642 }
643 void TIFFColorspace::create_objects()
644 {
645         add_item(new TIFFColorspaceItem(gui, FileTIFF::RGB_888));
646 //      add_item(new TIFFColorspaceItem(gui, FileTIFF::RGB_16161616));
647         add_item(new TIFFColorspaceItem(gui, FileTIFF::RGBA_8888));
648 //      add_item(new TIFFColorspaceItem(gui, FileTIFF::RGBA_16161616));
649         add_item(new TIFFColorspaceItem(gui, FileTIFF::RGB_FLOAT));
650         add_item(new TIFFColorspaceItem(gui, FileTIFF::RGBA_FLOAT));
651 }
652
653
654 TIFFColorspaceItem::TIFFColorspaceItem(TIFFConfigVideo *gui, int value)
655  : BC_MenuItem(FileTIFF::cmodel_to_str(value))
656 {
657         this->gui = gui;
658         this->value = value;
659 }
660 int TIFFColorspaceItem::handle_event()
661 {
662         gui->asset->tiff_cmodel = value;
663         return 0;
664 }
665
666
667
668
669
670
671
672 TIFFCompression::TIFFCompression(TIFFConfigVideo *gui, int x, int y, int w)
673  : BC_PopupMenu(x, y, w, FileTIFF::compression_to_str(gui->asset->tiff_compression))
674 {
675         this->gui = gui;
676 }
677 int TIFFCompression::handle_event()
678 {
679         return 1;
680 }
681 void TIFFCompression::create_objects()
682 {
683         add_item(new TIFFCompressionItem(gui, FileTIFF::NONE));
684 //      add_item(new TIFFCompressionItem(gui, FileTIFF::LZW));
685         add_item(new TIFFCompressionItem(gui, FileTIFF::PACK_BITS));
686 //      add_item(new TIFFCompressionItem(gui, FileTIFF::DEFLATE));
687 //      add_item(new TIFFCompressionItem(gui, FileTIFF::JPEG));
688 }
689
690
691
692
693
694 TIFFCompressionItem::TIFFCompressionItem(TIFFConfigVideo *gui, int value)
695  : BC_MenuItem(FileTIFF::compression_to_str(value))
696 {
697         this->gui = gui;
698         this->value = value;
699 }
700 int TIFFCompressionItem::handle_event()
701 {
702         gui->asset->tiff_compression = value;
703         return 0;
704 }
705
706
707