1 // ----------------------------------------------------------------------------
2 // MODULE : PResolutionFlashPix
3 // LANGUAGE : C++
4 // CREATOR : Philippe BOSSUT
5 // CREAT. DATE : Wednesday, March 20, 1996
6 // DESCRIPTION :
7 // COMMENTS :
8 // SCCSID : @(#)pres_fpx.cpp 1.6 13:18:52 02 Jun 1997
9 // ----------------------------------------------------------------------------
10 // Copyright (c) 1999 Digital Imaging Group, Inc.
11 // For conditions of distribution and use, see copyright notice
12 // in Flashpix.h
13 // ----------------------------------------------------------------------------
14
15 // ----------------------------------------------------------------------------
16 #include "pres_fpx.h"
17 // ----------------------------------------------------------------------------
18
19 // Includes
20 // --------
21
22 #include <string.h>
23 #include <stdio.h>
24
25 #if defined(USE_LEGACY_INCLUDES)
26 # include <fstream.h>
27 #else
28 # include <fstream>
29 using namespace std;
30 #endif
31
32 #ifdef macintosh
33 #include <Errors.h>
34 #endif
35 #ifndef Couleur_h
36 #include "fpx_color.h"
37 #endif
38 #ifndef Numbers_h
39 #include "numbers.h"
40 #endif
41 #ifndef Memoire_h
42 //include "b_memory.h"
43 #endif
44 #ifndef CorrectLut_h
45 #include "corr_lut.h"
46 #endif
47 #ifndef Debug_h
48 #include "debug.h"
49 #endif
50
51 #ifndef FileFlashPixIO_h
52 #include "f_fpxio.h"
53 #endif
54 #ifndef PTileFlashPix_h
55 #include "ptil_fpx.h"
56 #endif
57 #ifndef PImageFile_h
58 #include "pimgfile.h"
59 #endif
60 #ifndef FPXBaselineIO_h
61 #include "fpxlibio.h"
62 #endif
63 #ifndef FPXBaselineView_h
64 #include "fpxlib.h"
65 #endif
66
67
68
69 #ifndef OLECommun_h
70 #include "olecomm.h"
71 #endif
72 #ifndef OLECore_h
73 #include "olecore.h"
74 #endif
75 #ifndef OLEStorages_h
76 #include "olestorg.h"
77 #endif
78 #ifndef OLEHeaderStream_h
79 #include "olehstrm.h"
80 #endif
81 #ifndef OLEProperties_h
82 #include "oleprop.h"
83 #endif
84 #ifndef OLEPropertySet_h
85 #include "oleprops.h"
86 #endif
87 #ifndef OLEFiles_h
88 #include "olefiles.h"
89 #endif
90
91 #ifndef FlashPixUtils_h
92 #include "fpxutils.h"
93 #endif
94 #ifndef FlashPixFormat_h
95 #include "fpxformt.h"
96 #endif
97
98 // Constants
99 // ---------
100
101 // Variables
102 // ---------
103
104 // ----------------------------------------------------------------------------
105 // Internal Functions
106 // ----------------------------------------------------------------------------
107
108 // Convert a FPXColorspace element into a Subimage color data (see FPX Spec Table III.3)
109 // CAUTION: Algorithm limited to the Baseline spec.
110
111
ComputeChannelColor(DWORD * channelColor,FPXColorspace colorSpace,int index)112 static void ComputeChannelColor(DWORD* channelColor, FPXColorspace colorSpace, int index)
113 {
114 // Consistency check
115 assert (index < colorSpace.numberOfComponents);
116
117 // Default color space value: this works only in the Baseline environment with the
118 // hypothesis that only Baseline compliant colorspace are given in parameter.
119 TypColorSpace space = ColorSpace_Colorless;
120 TypColor color = Color_Unspecified;
121
122 // Determine the kind of color space coded in colorSpace
123 for (int i = 0; i < colorSpace.numberOfComponents; i++) {
124 switch (colorSpace.theComponents[i].myColor) {
125 case PHOTO_YCC_Y:
126 space = ColorSpace_PhotoYCC;
127 break;
128 case NIFRGB_R:
129 space = ColorSpace_NifRGB;
130 break;
131 case MONOCHROME:
132 space = ColorSpace_Monochrome;
133 break;
134 default:
135 {
136 }
137 }
138 }
139
140 // Determine the color component coded in colorSpace.theComponents[index]
141 switch (colorSpace.theComponents[index].myColor) {
142 case PHOTO_YCC_Y:
143 color = Color_PhotoYCC_Y;
144 break;
145 case PHOTO_YCC_C1:
146 color = Color_PhotoYCC_C1;
147 break;
148 case PHOTO_YCC_C2:
149 color = Color_PhotoYCC_C2;
150 break;
151 case NIFRGB_R:
152 color = Color_Red;
153 break;
154 case NIFRGB_G:
155 color = Color_Green;
156 break;
157 case NIFRGB_B:
158 color = Color_Blue;
159 break;
160 case ALPHA:
161 color = Color_Opacity;
162 break;
163 case MONOCHROME:
164 color = Color_Monochrome;
165 break;
166 }
167
168 // Build the color space subfield value
169 *channelColor = MakeColorSpec(space,color);
170
171 // Handle the calibrated/uncalibrated flag
172 if (colorSpace.isUncalibrated)
173 SetUncalibrated(*channelColor);
174 else
175 UnsetUncalibrated(*channelColor);
176 }
177
178
179 // ----------------------------------------------------------------------------
180 // Convert Subimage color data into a FPXColorspace element
181 // CAUTION: Algorithm limited to the Baseline spec.
AnalyseChannelColor(DWORD channelColor,FPXColorspace * colorSpace,int index)182 static void AnalyseChannelColor(DWORD channelColor, FPXColorspace* colorSpace, int index)
183 {
184 // Check the calibrated/uncalibrated bit
185 if (IsUncalibrated(channelColor))
186 colorSpace->isUncalibrated = TRUE;
187 else
188 colorSpace->isUncalibrated = FALSE;
189
190 // Unset the flag bits
191 UnsetPremultiplied(channelColor);
192 UnsetUncalibrated(channelColor);
193
194 // Analyse the color space according to Baseline rules. See Table III.6 of the FPX spec.
195 switch (channelColor) {
196 case MakeColorSpec(ColorSpace_Colorless,Color_Opacity):
197 colorSpace->theComponents[index].myColor = ALPHA;
198 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
199 break;
200 case MakeColorSpec(ColorSpace_Monochrome,Color_Monochrome):
201 colorSpace->theComponents[index].myColor = MONOCHROME;
202 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
203 break;
204 case MakeColorSpec(ColorSpace_Monochrome,Color_Opacity):
205 colorSpace->theComponents[index].myColor = ALPHA;
206 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
207 break;
208 case MakeColorSpec(ColorSpace_PhotoYCC,Color_PhotoYCC_Y):
209 colorSpace->theComponents[index].myColor = PHOTO_YCC_Y;
210 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
211 break;
212 case MakeColorSpec(ColorSpace_PhotoYCC,Color_PhotoYCC_C1):
213 colorSpace->theComponents[index].myColor = PHOTO_YCC_C1;
214 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
215 break;
216 case MakeColorSpec(ColorSpace_PhotoYCC,Color_PhotoYCC_C2):
217 colorSpace->theComponents[index].myColor = PHOTO_YCC_C2;
218 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
219 break;
220 case MakeColorSpec(ColorSpace_PhotoYCC,Color_Opacity):
221 colorSpace->theComponents[index].myColor = ALPHA;
222 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
223 break;
224 case MakeColorSpec(ColorSpace_RGB,Color_Red): // treat unspecified RGB just like NIF RGB
225 case MakeColorSpec(ColorSpace_NifRGB,Color_Red):
226 colorSpace->theComponents[index].myColor = NIFRGB_R;
227 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
228 break;
229 case MakeColorSpec(ColorSpace_RGB,Color_Green): // treat unspecified RGB just like NIF RGB
230 case MakeColorSpec(ColorSpace_NifRGB,Color_Green):
231 colorSpace->theComponents[index].myColor = NIFRGB_G;
232 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
233 break;
234 case MakeColorSpec(ColorSpace_RGB,Color_Blue): // treat unspecified RGB just like NIF RGB
235 case MakeColorSpec(ColorSpace_NifRGB,Color_Blue):
236 colorSpace->theComponents[index].myColor = NIFRGB_B;
237 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
238 break;
239 case MakeColorSpec(ColorSpace_RGB,Color_Opacity): // treat unspecified RGB just like NIF RGB
240 case MakeColorSpec(ColorSpace_NifRGB,Color_Opacity):
241 colorSpace->theComponents[index].myColor = ALPHA;
242 colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
243 break;
244 default:
245 assert(false);
246 break;
247 }
248 }
249
250 // ----------------------------------------------------------------------------
251 // Member Functions
252 // ----------------------------------------------------------------------------
253
254 // ----------------------------------------------------------------------------
255 // Methods of the PResolutionFlashPix class : this is the Resolution object
256 //
257 // Manage an array on PTileFlashPix objects which contain pixels
258 // Each PResolutionFlashPix points to the next which has a resolution 1/4.
259 // ----------------------------------------------------------------------------
260
261 // Initialize resolution information and create the next sub-image
262 // Use this constructor in Read or Write mode
PResolutionFlashPix(PHierarchicalImage * father,int * offset,int id)263 PResolutionFlashPix::PResolutionFlashPix (PHierarchicalImage* father, int* offset, int id) :
264 PResolutionLevel (father, offset, id)
265 {
266 Init();
267 }
268
269
270 // ----------------------------------------------------------------------------
271 // Initialize resolution information and create the next sub-image
272 // Use this constructor in Create mode
PResolutionFlashPix(PHierarchicalImage * father,int width,int height,int * whatImage)273 PResolutionFlashPix::PResolutionFlashPix (PHierarchicalImage* father, int width, int height, int* whatImage) :
274 PResolutionLevel (father, width, height, whatImage)
275 {
276 Init();
277 }
278
279
280 // ----------------------------------------------------------------------------
281 // Clean resolution level and delete all related objects
~PResolutionFlashPix()282 PResolutionFlashPix::~PResolutionFlashPix()
283 {
284 if (tiles) {
285 delete [] tiles;
286 tiles = NULL;
287 }
288
289 // Delete jpeg header if it exists
290 if ( jpegHeader )
291 delete[] jpegHeader;
292
293 // CAUTION: delete streams before the storage which contain them
294 // Commit() makes sure that everything has been written on the disk (flush
295 // all ole buffers for the element) and delete releases the OLE object.
296
297 if (subStreamHdr) {
298 subStreamHdr->Commit();
299 delete subStreamHdr;
300 subStreamHdr = NULL;
301 }
302 if (subStreamData) {
303 subStreamData->Commit();
304 delete subStreamData;
305 subStreamData = NULL;
306 }
307 if (subStorage) {
308 subStorage->Commit();
309 delete subStorage;
310 subStorage = NULL;
311 }
312 }
313
314
315 // ----------------------------------------------------------------------------
AllocTilesArray()316 FPXStatus PResolutionFlashPix::AllocTilesArray ()
317 {
318 tiles = new PTileFlashPix[nbTilesH * nbTilesW];
319 return ((tiles == NULL)? FPX_MEMORY_ALLOCATION_FAILED : FPX_OK);
320 }
321
322
323 // ----------------------------------------------------------------------------
Init()324 void PResolutionFlashPix::Init ()
325 {
326 baseSpace = ((PFileFlashPixIO*)fatherFile)->baseSpace;
327 CreateFPXColorSpace (baseSpace, &colorSpace);
328 colorSpace.isUncalibrated = ((PFileFlashPixIO*)fatherFile)->baseUncalibrated;
329 nbChannels = colorSpace.numberOfComponents;
330 isAlpha = IsAlphaBaseline(baseSpace);
331 premultiplied = true; // always premultiplied by default in Baseline FlashPix
332 alphaOffset = (unsigned char) GetAlphaOffsetBaseline(baseSpace);
333 isICCprofile = false;
334 ICCprofile = 0;
335
336 compression = ((PFileFlashPixIO*)fatherFile)->FPXCompression;
337 compressionSubtype = ((PFileFlashPixIO*)fatherFile)->FPXCompressionSubType;
338 qualityFactor = ((PFileFlashPixIO*)fatherFile)->FPXQualityFactor;
339 compressTableGroup = GET_JPEGTablesIndex(compressionSubtype); // Set initial jpeg table id
340 jpegHeader = NULL; // Set initial jpeg table pointer to null
341 headerSize = 0; // Set initial jpeg table length
342
343 subStreamHdr = NULL;
344 subStreamData = NULL;
345 subStorage = NULL;
346 }
347
348
349 // ----------------------------------------------------------------------------
CreateHeaderStream()350 FPXStatus PResolutionFlashPix::CreateHeaderStream ()
351 {
352 // Create the Storage and the Streams to store the data
353 PFlashPixFile *fileFPX = (PFlashPixFile*)fatherFile->filePtr;
354 FPXStatus status = FPX_OK;
355 char resolutionName [33];
356 char streamHdrName[33];
357 char streamDataName[33];
358
359 // the number associate to the resolution is the inverse than the one use internaly
360 // because in FlashPix the resolution 0 is the lowest resolution
361 GetResolutionName(resolutionName, fatherFile->nbSubImages - identifier - 1);
362
363 // Baseline special: there is only 1 sub image level per resolution and 0 support data
364 GetSubImageHdrName(streamHdrName, 0);
365 GetSubImageDataName(streamDataName, 0);
366
367 CLSID clsID = ID_Resolution;
368 if (fileFPX->CreateStorage (clsID, resolutionName, &subStorage)) {
369 CLSID clsID = ID_SubImageHdr;
370 if (subStorage->CreateHeaderStream (clsID, streamHdrName, &subStreamHdr)) {
371 CLSID clsID = ID_SubImageData;
372 if (subStorage->CreateHeaderStream (clsID, streamDataName, &subStreamData)) {
373 Allocation();
374 } else
375 status = FPX_FILE_CREATE_ERROR;
376 } else
377 status = FPX_FILE_CREATE_ERROR;
378 } else
379 status = FPX_FILE_CREATE_ERROR;
380
381 // Update the number of resolution level created for this file
382 if (status == FPX_OK)
383 ((PFileFlashPixIO*)fatherFile)->nbCreatedResolutions++;
384
385 return status;
386 }
387
388
389 // ----------------------------------------------------------------------------
ReadHeaderStream()390 FPXStatus PResolutionFlashPix::ReadHeaderStream ()
391 {
392 // Open the Storage and the Streams to read or write the data
393 PFlashPixFile* fileFPX = (PFlashPixFile*)fatherFile->filePtr;
394 FPXStatus status = FPX_OK;
395 char resolutionName [33];
396 char streamHdrName[33];
397 char streamDataName[33];
398
399 // The number associated to the resolution is the inverse than the one used internaly
400 // because in FlashPix the resolution 0 is the lowest resolution
401 GetResolutionName(resolutionName, fatherFile->nbSubImages - identifier - 1);
402
403 // Baseline special: there is only 1 sub image level per resolution and 0 support data
404 GetSubImageHdrName(streamHdrName, 0);
405 GetSubImageDataName(streamDataName, 0);
406
407 CLSID clsID = ID_Resolution;
408 if (fileFPX->OpenStorage (clsID, resolutionName, &subStorage)) {
409 CLSID clsID = ID_SubImageHdr;
410 if (subStorage->OpenHeaderStream (clsID, streamHdrName, &subStreamHdr)) {
411 CLSID clsID = ID_SubImageData;
412 if (subStorage->OpenHeaderStream (clsID, streamDataName, &subStreamData))
413 status = Read (); // Create block array and read sub-image information
414 else
415 status = FPX_FILE_READ_ERROR;
416 } else
417 status = FPX_FILE_READ_ERROR;
418 } else
419 status = FPX_FILE_READ_ERROR;
420
421 if ((status == FPX_OK) && (tiles == NULL)) // If failed, raise an error
422 status = FPX_ERROR;
423
424 if (status)
425 imageStatus = status;
426 return status;
427 }
428
429
430 // ----------------------------------------------------------------------------
UpdateHeaderStream()431 FPXStatus PResolutionFlashPix::UpdateHeaderStream ()
432 {
433 FPXStatus status = FPX_OK;
434
435 // Try to read the header stream first
436 status = ReadHeaderStream ();
437
438 // If failed, try to create the header stream
439 if (status != FPX_OK)
440 status = CreateHeaderStream();
441
442 if ((status == FPX_OK) && (tiles == NULL)) // If failed, raise an error
443 status = FPX_ERROR;
444
445 if (status)
446 imageStatus = status;
447 return status;
448 }
449
450
451 // ----------------------------------------------------------------------------
GetResolutionDescription()452 FPXStatus PResolutionFlashPix::GetResolutionDescription()
453 {
454 PFlashPixFile *fileFPX = (PFlashPixFile*)fatherFile->filePtr;
455 FPXStatus status = FPX_OK;
456 OLEProperty *aProp;
457 int FlashPixIdentifier = fatherFile->nbSubImages - identifier - 1;
458
459 // SubImage pixel width (required)
460 if (fileFPX->GetImageContentProperty (PID_SubImageWidth(FlashPixIdentifier), &aProp))
461 realWidth = int(*aProp);
462 else
463 status = FPX_FILE_READ_ERROR;
464
465 // Subimage pixel heigth (required)
466 if (fileFPX->GetImageContentProperty (PID_SubImageHeight(FlashPixIdentifier), &aProp))
467 realHeight = int(*aProp);
468 else
469 status = FPX_FILE_READ_ERROR;
470
471 // Subimage color (required)
472 if (fileFPX->GetImageContentProperty (PID_SubImageColor(FlashPixIdentifier), &aProp)) {
473
474 OLEBlob colorBlob((const BLOB*)(*aProp));
475 if (colorBlob.GetBlobSize()>0) {
476
477 DWORD tmp, tmp0;
478 Boolean uncalibrated = false;
479
480 colorBlob.ReadVT_I4(&tmp); // Number of subimages
481 assert (tmp == 1); // Only 1 subimage in Baseline
482
483 colorBlob.ReadVT_I4(&tmp); // Number of channels
484 assert (tmp <= FPX_MAX_COMPONENTS); // Baseline limitation: RGB (or YCC) + alpha
485 colorSpace.numberOfComponents = (short)(tmp);
486 nbChannels = (short)(tmp);
487
488 colorBlob.ReadVT_I4(&tmp0); // Color of channel 0
489 premultiplied = IsPremultiplied(tmp0);
490
491 uncalibrated = IsUncalibrated(tmp0);
492 if( uncalibrated == true )
493 ((PFileFlashPixIO*)fatherFile)->SetUncalibratedFlag(uncalibrated);
494
495 AnalyseChannelColor(tmp0,&colorSpace,0);
496 ExtractColorSpace(tmp0);
497
498 for (int i = 1; i < colorSpace.numberOfComponents; i++) {
499 colorBlob.ReadVT_I4(&tmp); // Color of channel i
500 AnalyseChannelColor(tmp,&colorSpace,i);
501 premultiplied |= IsPremultiplied(tmp);
502 assert ((ExtractColorSpace(tmp)) == tmp0); // The color space part must be the same for all channels
503 // CAUTION: we don't analyse extra subimages (Baseline limitation)
504 }
505
506 // Update the easy to use Baseline description...
507 baseSpace = AnalyseFPXColorSpace(colorSpace);
508 assert (baseSpace != NON_AUTHORIZED_SPACE);
509 isAlpha = IsAlphaBaseline(baseSpace);
510 alphaOffset = (unsigned char) GetAlphaOffsetBaseline(baseSpace);
511 } else
512 status = FPX_FILE_READ_ERROR;
513
514 } else
515 status = FPX_FILE_READ_ERROR;
516
517 // Subimage numerical format (required)
518 if (fileFPX->GetImageContentProperty (PID_SubImageNumFormat(FlashPixIdentifier), &aProp)) {
519 const VECTOR *vector = (const VECTOR *)(*aProp);
520 assert (vector->cElements == 1); // Only one subimage in Baseline
521 assert (vector->prgdw[0] == VT_UI1); // Always 8-bit unsigned integer in Baseline
522 } else
523 status = FPX_FILE_READ_ERROR;
524
525 // Decimation method (required)
526 if (fileFPX->GetImageContentProperty (PID_DecimationMethod(FlashPixIdentifier), &aProp)) {
527 DWORD decimation;
528 decimation = int(*aProp);
529 switch (decimation) {
530 case 0:
531 // For the high resolution level, there is no decimation and it's the only case...
532 assert (identifier == 0);
533 break;
534 case 2: // 2x2 averaging
535 fatherFile->convolution = Convolution_Standard;
536 break;
537 case 4: // 4x4 gaussian filter
538 fatherFile->convolution = Convolution_Gauss;
539 break;
540 // case DecimationStandard: // Default filter (still to be defined...)
541 // fatherFile->convolution = Convolution_FlashPix;
542 // break;
543 default:
544 // Not supported decimation method
545 // djk 14Apr1997 AI#18295: removed assert(false)
546 fatherFile->convolution = Convolution_Standard;
547 break;
548 }
549 } else
550 status = FPX_FILE_READ_ERROR;
551
552 // Decimation prefilter width (optional)
553
554 // Subimage attributes (optional)
555 // NOT SPECIFIED
556
557 // Subimage ICC profile (optional)
558
559 // Support data contents (optional)
560 // NOT SPECIFIED
561
562 return status;
563 }
564
565
566 // ----------------------------------------------------------------------------
SetResolutionDescription()567 FPXStatus PResolutionFlashPix::SetResolutionDescription()
568 {
569 PFlashPixFile *fileFPX = (PFlashPixFile*)fatherFile->filePtr;
570 FPXStatus status = FPX_OK;
571 OLEProperty *aProp;
572 int FlashPixIdentifier = fatherFile->nbSubImages - identifier - 1;
573
574 // SubImage pixel width (required)
575 if (fileFPX->SetImageContentProperty (PID_SubImageWidth(FlashPixIdentifier) , TYP_SubImageWidth, &aProp)) { // Subimage width
576 *aProp = int(realWidth);
577 } else
578 status = FPX_FILE_WRITE_ERROR;
579
580 // Subimage pixel heigth (required)
581 if (fileFPX->SetImageContentProperty (PID_SubImageHeight(FlashPixIdentifier), TYP_SubImageHeight, &aProp)) { // Subimage heigth
582 *aProp = int(realHeight);
583 } else
584 status = FPX_FILE_WRITE_ERROR;
585
586 // Subimage color (required)
587 if (fileFPX->SetImageContentProperty (PID_SubImageColor(FlashPixIdentifier), TYP_SubImageColor, &aProp)) {
588 OLEBlob colorBlob(8 + 4*colorSpace.numberOfComponents);
589 if (colorBlob.GetBlobSize()>0) {
590 DWORD tmp = 1;
591 colorBlob.WriteVT_I4(tmp); // Number of subimages (only 1 subimage in Baseline...)
592 tmp = (DWORD)(colorSpace.numberOfComponents);
593 colorBlob.WriteVT_I4(tmp); // Number of channels
594 for (int i = 0; i < colorSpace.numberOfComponents; i++) {
595 ComputeChannelColor(&tmp,colorSpace,i); // Color of channel i
596 if (isAlpha) {
597 if (colorSpace.theComponents[i].myColor == ALPHA)
598 UnsetPremultiplied(tmp);
599 else if (premultiplied)
600 SetPremultiplied(tmp);
601 else
602 UnsetPremultiplied(tmp);
603 }
604 colorBlob.WriteVT_I4(tmp);
605 // CAUTION: we don't analyse extra subimages (Baseline limitation)
606 }
607 *aProp = (BLOB*)(colorBlob.GetBlob());
608 } else
609 status = FPX_FILE_WRITE_ERROR;
610 } else
611 status = FPX_FILE_WRITE_ERROR;
612
613 // Subimage numerical format (required)
614 if (fileFPX->SetImageContentProperty (PID_SubImageNumFormat(FlashPixIdentifier), TYP_SubImageNumFormat, &aProp)) { // Subimage numerical format
615 uint32_t format = VT_UI1; // Always 8-bit unsigned integer in Baseline
616 FPXLongArray numericalFormat;
617 numericalFormat.length = 1; // Only one subimage in Baseline
618 numericalFormat.ptr = &format;
619 *aProp = numericalFormat;
620 } else
621 status = FPX_FILE_WRITE_ERROR;
622
623 // Decimation method (required)
624 if (fileFPX->SetImageContentProperty (PID_DecimationMethod(FlashPixIdentifier), TYP_DecimationMethod, &aProp)) { // Subimage decimation method
625 DWORD decimation;
626 switch (fatherFile->convolution) {
627 case Convolution_Standard: // 2x2 averaging
628 decimation = 2;
629 break;
630 case Convolution_Gauss: // 4x4 gaussian filter
631 decimation = 4;
632 break;
633 // case Convolution_FlashPix: // Recommended filter (still to be defined...)
634 // decimation = DecimationStandard;
635 // break;
636 default:
637 {
638 }
639 }
640 if (identifier == 0) // For the high resolution level, there is no decimation
641 decimation = 0;
642 *aProp = int(decimation);
643 } else
644 status = FPX_FILE_WRITE_ERROR;
645
646 // Decimation prefilter width (optionnal)
647
648 // Subimage attributes (optionnal)
649 // NOT SPECIFIED
650
651 // Subimage ICC profile (optionnal)
652
653 // Support data contents (optionnal)
654 // NOT SPECIFIED
655
656 return status;
657 }
658
659
660 // ----------------------------------------------------------------------------
661 // Read a resolution level and initialize the buffer 'pixels'
Read()662 FPXStatus PResolutionFlashPix::Read ()
663 {
664 int i;
665 DWORD tmp;
666 DWORD n;
667 FPXStatus status = FPX_OK;
668 DWORD lengthInfoStream, tileWidth, tileHeight, nbChannel, headersTableOffset;
669 DWORD tileHeadersize, offsetTile, sizeTile, compressType;
670
671 // The stream must be opened or created before calling Read()...
672 if (subStreamHdr == NULL)
673 return FPX_FILE_NOT_OPEN_ERROR;
674
675 if (subStreamHdr->Seek(0)) { // Position to the beginning of the header stream
676
677 // Read the Subimage Header Stream
678 if (subStreamHdr->ReadVT_I4(&lengthInfoStream) == 0) // length of the info stream
679 status = FPX_FILE_READ_ERROR;
680 if (subStreamHdr->ReadVT_I4(&tmp) == 0) // Width of sub-image in pixels
681 status = FPX_FILE_READ_ERROR;
682 realWidth = tmp;
683 if (subStreamHdr->ReadVT_I4(&tmp) == 0) // Height of sub-image in pixels
684 status = FPX_FILE_READ_ERROR;
685 realHeight = tmp;
686 if (subStreamHdr->ReadVT_I4(&n) == 0) // nb of tiles in the sub-image
687 status = FPX_FILE_READ_ERROR;
688 if (subStreamHdr->ReadVT_I4(&tileWidth) == 0) // Tiles width
689 status = FPX_FILE_READ_ERROR;
690 if (subStreamHdr->ReadVT_I4(&tileHeight) == 0) // Tiles height
691 status = FPX_FILE_READ_ERROR;
692 if (subStreamHdr->ReadVT_I4(&nbChannel) == 0) // number of channels
693 status = FPX_FILE_READ_ERROR;
694 if (subStreamHdr->ReadVT_I4(&headersTableOffset) == 0) // Tile headers table offset
695 status = FPX_FILE_READ_ERROR;
696 if (subStreamHdr->ReadVT_I4(&tileHeadersize) == 0) // Tile Header length
697 status = FPX_FILE_READ_ERROR;
698
699 assert(tileHeadersize == 16); // Should be 16 in Baseline...
700 tileHeadersize = 16;
701
702 // Compute numbers of tiles in the width and the height of the resolution level
703 nbTilesH = (short) (realHeight/tileHeight + (realHeight%tileHeight ? 1 : 0));
704 nbTilesW = (short) (realWidth /tileWidth + (realWidth %tileWidth ? 1 : 0));
705
706 // Test values consistency
707 if ((!realHeight) || (!realWidth) || (!nbTilesH) || (!nbTilesW))
708 n = 0;
709
710 int offset = headersTableOffset; // Position to the tile table
711
712 if (status == FPX_OK) {
713 AllocTilesArray ();
714 for (i = 0; i < (int) n; i++) {
715 if (subStreamHdr->Seek(offset) == false) // Offset of each tile of the sub-image in the file
716 status = FPX_FILE_READ_ERROR;
717 if (subStreamHdr->ReadVT_I4(&offsetTile) == 0) // Offset of each tile of the sub-image in the file
718 status = FPX_FILE_READ_ERROR;
719 if (subStreamHdr->ReadVT_I4(&sizeTile) == 0) // Size of each tile
720 status = FPX_FILE_READ_ERROR;
721 if (subStreamHdr->ReadVT_I4(&compressType) == 0) // Compression type
722 status = FPX_FILE_READ_ERROR;
723 if (subStreamHdr->ReadVT_I4((DWORD *)&compressionSubtype) == 0) // Sub-compression type
724 status = FPX_FILE_READ_ERROR;
725
726 // Break and exit if error
727 if (status != FPX_OK)
728 break;
729
730 compression = (FPXCompressionOption)compressType;
731 tiles[i].InitializeRead(this,offsetTile,sizeTile,i, compressType, compressionSubtype);
732 offset += tileHeadersize;
733 }
734 }
735 }
736
737 // Error handling
738 if (status != FPX_OK) {
739 fatherFile->filePtr->SignaleErreur();
740 delete [] tiles;
741 tiles = NULL;
742 realHeight = 0;
743 realWidth = 0;
744 nbTilesH = 0;
745 nbTilesW = 0;
746 }
747
748 return (status);
749 }
750
751
752 // ----------------------------------------------------------------------------
753 // Write the tile header of a sub-image :
Write()754 FPXStatus PResolutionFlashPix::Write()
755 {
756 register int TILE_WIDTH = fatherFile->tileWidth;
757 FPXStatus status = FPX_OK;
758
759 // If nothing has never been writen or read from this resolution level,
760 // there's no point to save anything in the subStreamHdr...
761 if (!HasBeenUsed())
762 return FPX_OK;
763
764 if (subStreamHdr->Seek(0)) { // Position to the beginning of the header stream
765
766 DWORD offset = 36; // 9 fields of 4 bytes each in this version...
767 DWORD n = nbTilesH * nbTilesW; // number of tiles
768 DWORD tileWidth = TILE_WIDTH; // Fixed and equal to 64 in Baseline...
769 DWORD nbChannel = GetNbChannel(baseSpace); // Number of channels
770 DWORD length = 16; // 4 fileds of 4 bytes each in this version...
771 DWORD tmp;
772
773 // Write the SubImage Header Stream header
774 if (subStreamHdr->WriteVT_I4(&offset) == 0) // Length of header stream header
775 status = FPX_FILE_WRITE_ERROR;
776 tmp = realWidth;
777 if (subStreamHdr->WriteVT_I4(&tmp) == 0) // Width of the sub-images in pixels
778 status = FPX_FILE_WRITE_ERROR;
779 tmp = realHeight;
780 if (subStreamHdr->WriteVT_I4(&tmp) == 0) // Height of the sub-images in pixels
781 status = FPX_FILE_WRITE_ERROR;
782 if (subStreamHdr->WriteVT_I4(&n) == 0) // nb of tiles of the sub-image
783 status = FPX_FILE_WRITE_ERROR;
784 if (subStreamHdr->WriteVT_I4(&tileWidth) == 0) // Tiles width
785 status = FPX_FILE_WRITE_ERROR;
786 if (subStreamHdr->WriteVT_I4(&tileWidth) == 0) // Tiles height (the same in Baseline...)
787 status = FPX_FILE_WRITE_ERROR;
788 if (subStreamHdr->WriteVT_I4(&nbChannel) == 0) // Number of channels
789 status = FPX_FILE_WRITE_ERROR;
790 if (subStreamHdr->WriteVT_I4(&offset) == 0) // Tile header table offset
791 status = FPX_FILE_WRITE_ERROR;
792 if (subStreamHdr->WriteVT_I4(&length) == 0) // Tile header table offset
793 status = FPX_FILE_WRITE_ERROR;
794
795 // Write the Tile Header Table
796 if (status == FPX_OK) {
797
798 // For each tile
799 for (int i = 0; i < (int) n; i++) {
800
801 // Get the pointer for this tile
802 PTileFlashPix* pt = (PTileFlashPix*)(tiles + i);
803
804 // If this tile has never been written before, initialize it with background color
805 int offset = pt->GetposFic();
806 if ( (offset < 0 ) && (pt->compression != SINGLE_COLOR)) { // PTCH_NEGONE
807 pt->tileInitialize = TRUE;
808
809 // Set the compression to single color and write tile
810 pt->SetCompression(SINGLE_COLOR);
811 pt->WriteTile();
812 }
813
814 // Get the infos for this tile
815 offset = pt->GetposFic();
816 DWORD size = pt->GetTileSize();
817 DWORD blocCompr = (DWORD)pt->compression;
818 DWORD blocSubtype = (DWORD)pt->compressionSubtype;
819
820 // Change compression type to 2 (JPEG) only
821 if ( pt->compression == JPEG_BY_QUALITY || pt->compression == JPEG_BY_TABLE_GROUP )
822 blocCompr = JPEG_UNSPECIFIED;
823
824 // Write the Tile Header for this tile
825 if (subStreamHdr->WriteVT_I4((DWORD *)&offset) == 0)// Write the offset of each tile of the sub-image in the file
826 status = FPX_FILE_WRITE_ERROR;
827 if (subStreamHdr->WriteVT_I4(&size) == 0) // Write the size of each tile
828 status = FPX_FILE_WRITE_ERROR;
829 if (subStreamHdr->WriteVT_I4(&blocCompr) == 0) // Write the compression type
830 status = FPX_FILE_WRITE_ERROR;
831 if (subStreamHdr->WriteVT_I4(&blocSubtype) == 0) // Write the sub-compression type
832 status = FPX_FILE_WRITE_ERROR;
833
834 // Break and exit if error
835 if (status != FPX_OK)
836 break;
837 }
838 }
839 }
840
841 return (status);
842 }
843
844
845 // ----------------------------------------------------------------------------
846 // Read the tile data from the file without decompression
ReadRawTile(unsigned int whichTile,FPXCompressionOption * compressOption,unsigned char * compressQuality,long * compressSubtype,unsigned int * dataLength,void ** data)847 FPXStatus PResolutionFlashPix::ReadRawTile (
848 unsigned int whichTile,
849 FPXCompressionOption* compressOption,
850 unsigned char* compressQuality,
851 long* compressSubtype,
852 unsigned int* dataLength,
853 void** data)
854 {
855 FPXStatus status = FPX_OK;
856
857 // Read and allocate tile pointers if necessary
858 if (!HasBeenUsed()) {
859 status = ReadHeaderStream();
860 if(status != FPX_OK)
861 return status;
862 }
863
864 if (status == 0) {
865 unsigned long nbTiles = nbTilesW * nbTilesH;
866 if (whichTile >= nbTiles)
867 status = FPX_BAD_COORDINATES;
868 else {
869 PTileFlashPix* tile = (PTileFlashPix*)(tiles) + whichTile;
870 status = tile->ReadRawTile (compressOption, compressQuality, compressSubtype, dataLength, data);
871 }
872 }
873 return status;
874 }
875
876
877 // ----------------------------------------------------------------------------
878 // Write the tile data in the file without compression
WriteRawTile(unsigned int whichTile,FPXCompressionOption compressOption,unsigned char compressQuality,long compressSubtype,unsigned int dataLength,void * data)879 FPXStatus PResolutionFlashPix::WriteRawTile (
880 unsigned int whichTile,
881 FPXCompressionOption compressOption,
882 unsigned char compressQuality,
883 long compressSubtype,
884 unsigned int dataLength,
885 void* data)
886 {
887 FPXStatus status = FPX_OK;
888
889 // Read and allocate tile pointers if necessary
890 if (!HasBeenUsed())
891 status = UpdateHeaderStream();
892
893 if (status == FPX_OK) {
894 unsigned int nbTiles = nbTilesW * nbTilesH;
895 if (whichTile >= nbTiles)
896 status = FPX_BAD_COORDINATES;
897 else {
898 PTileFlashPix* tile = (PTileFlashPix*)(tiles) + whichTile;
899 status = tile->WriteRawTile (compressOption, compressQuality, compressSubtype, dataLength, data);
900 }
901 }
902 return status;
903 }
904
905
906 // ----------------------------------------------------------------------------
WriteLine(Pixel * pix,short plan)907 FPXStatus PResolutionFlashPix::WriteLine (Pixel* pix, short plan)
908 {
909 FPXStatus status = FPX_OK;
910
911 // Read and allocate tile pointers if necessary
912 if (!HasBeenUsed())
913 status = UpdateHeaderStream();
914
915 // Call the parent method now
916 if (status == FPX_OK)
917 status = PResolutionLevel::WriteLine(pix, plan);
918
919 return status;
920 }
921
922
923 // ----------------------------------------------------------------------------
FlushModifiedTiles()924 FPXStatus PResolutionFlashPix::FlushModifiedTiles()
925 {
926 return PResolutionLevel::FlushModifiedTiles() ;
927 }
928
929
930 // ----------------------------------------------------------------------------
Convolution(int x,int y,Pixel * pix,int width,int height)931 FPXStatus PResolutionFlashPix::Convolution (int x, int y, Pixel* pix, int width, int height)
932 {
933 FPXStatus status = FPX_OK;
934
935 // Read and allocate tile pointers if necessary
936 if (!HasBeenUsed())
937 status = UpdateHeaderStream();
938
939 // Call the parent method now
940 if (status == FPX_OK)
941 status = PResolutionLevel::Convolution (x, y, pix, width, height);
942
943 return status;
944 }
945
946
947 // ----------------------------------------------------------------------------
DecimateLevel()948 FPXStatus PResolutionFlashPix::DecimateLevel ()
949 {
950 FPXStatus status = FPX_OK;
951
952 // Read and allocate tile pointers if necessary
953 if (!HasBeenUsed())
954 status = UpdateHeaderStream();
955
956 // Call the parent method now
957 if (status == FPX_OK)
958 status = PResolutionLevel::DecimateLevel();
959
960 return status;
961 }
962
963
964 // ----------------------------------------------------------------------------
WriteRectangle(int x0,int y0,int x1,int y1,Pixel * pix,short plan)965 FPXStatus PResolutionFlashPix::WriteRectangle (int x0, int y0, int x1, int y1, Pixel* pix, short plan)
966 {
967 FPXStatus status = FPX_OK;
968
969 // Read and allocate tile pointers if necessary
970 if (!HasBeenUsed())
971 status = UpdateHeaderStream();
972
973 // Call the parent method now
974 if (status == FPX_OK)
975 status = PResolutionLevel::WriteRectangle(x0, y0, x1, y1, pix, plan);
976
977 return status;
978 }
979
980
981 // ----------------------------------------------------------------------------
ReadRectangle(int x0,int y0,int x1,int y1,Pixel * pix)982 FPXStatus PResolutionFlashPix::ReadRectangle (int x0, int y0, int x1, int y1, Pixel* pix)
983 {
984 FPXStatus status = FPX_OK;
985
986 // Read and allocate tile pointers if necessary
987 if (!HasBeenUsed())
988 status = ReadHeaderStream();
989
990 // Call the parent method now
991 if (status == FPX_OK)
992 status = PResolutionLevel::ReadRectangle(x0, y0, x1, y1, pix);
993
994 return status;
995 }
996
997
998 // ----------------------------------------------------------------------------
ReadInARectangle(Pixel * bufferOut,short pixelsPerLine,short width,short height,const CorrectLut * correctLut,Boolean useAlphaChannel,const CombinMat * combinaisonMatrix)999 FPXStatus PResolutionFlashPix::ReadInARectangle (Pixel* bufferOut, short pixelsPerLine, short width, short height,
1000 const CorrectLut* correctLut, Boolean useAlphaChannel, const CombinMat* combinaisonMatrix)
1001 {
1002 FPXStatus status = FPX_OK;
1003
1004 // Read and allocate tile pointers if necessary
1005 if (!HasBeenUsed())
1006 status = ReadHeaderStream();
1007
1008 // Call the parent method now
1009 if (status == 0)
1010 status = PResolutionLevel::ReadInARectangle (bufferOut, pixelsPerLine, width, height,
1011 correctLut, useAlphaChannel, combinaisonMatrix);
1012 return status;
1013 }
1014
1015
1016 // ----------------------------------------------------------------------------
Read(int * px,int * py,Pixel * table)1017 FPXStatus PResolutionFlashPix::Read (int* px, int* py, Pixel* table)
1018 {
1019 FPXStatus status = FPX_OK;
1020
1021 // Read and allocate tile pointers if necessary
1022 if (!HasBeenUsed())
1023 status = ReadHeaderStream();
1024
1025 // Call the parent method now
1026 if (status == FPX_OK)
1027 status = PResolutionLevel::Read (px, py, table);
1028
1029 return status;
1030 }
1031
1032
1033 // ----------------------------------------------------------------------------
ReadInterpolated(int * px,int * py,Pixel * table)1034 FPXStatus PResolutionFlashPix::ReadInterpolated (int* px, int* py, Pixel* table)
1035 {
1036 FPXStatus status = FPX_OK;
1037
1038 // Read and allocate tile pointers if necessary
1039 if (!HasBeenUsed())
1040 status = ReadHeaderStream();
1041
1042 // Call the parent method now
1043 if (status == FPX_OK)
1044 status = PResolutionLevel::ReadInterpolated (px, py, table);
1045
1046 return status;
1047 }
1048
1049
1050 // ----------------------------------------------------------------------------
ReadMeanInterpolated(int xi,int yi,Pixel & pixel)1051 FPXStatus PResolutionFlashPix::ReadMeanInterpolated (int xi, int yi, Pixel& pixel)
1052 {
1053 FPXStatus status = FPX_OK;
1054
1055 // Read and allocate tile pointers if necessary
1056 if (!HasBeenUsed())
1057 status = ReadHeaderStream();
1058
1059 // Call the parent method now
1060 if (status == FPX_OK)
1061 status = PResolutionLevel::ReadMeanInterpolated (xi, yi, pixel);
1062
1063 return status;
1064 }
1065
1066
1067 // ----------------------------------------------------------------------------
IsOnTheBorder(int xi,int yi)1068 Boolean PResolutionFlashPix::IsOnTheBorder (int xi, int yi)
1069 {
1070 Boolean ok = true;
1071
1072 // Read and allocate tile pointers if necessary
1073 if (!HasBeenUsed()) {
1074 if (UpdateHeaderStream() != FPX_OK)
1075 ok = false;
1076 }
1077
1078 // Call the parent method now
1079 if (ok)
1080 ok = PResolutionLevel::IsOnTheBorder (xi, yi);
1081
1082 return ok;
1083 }
1084
1085
1086 // ----------------------------------------------------------------------------
1087 // Compute histogram for the 4 channels
GetHistogram(int * alpha,int * red,int * green,int * blue,int * brightness,const CorrectLut * correctLut)1088 FPXStatus PResolutionFlashPix::GetHistogram (int* alpha, int* red, int* green, int* blue, int* brightness, const CorrectLut* correctLut)
1089 {
1090 FPXStatus status = FPX_OK;
1091
1092 // Read and allocate tile pointers if necessary
1093 if (!HasBeenUsed())
1094 status = UpdateHeaderStream();
1095
1096 // Call the parent method now
1097 if (status == 0)
1098 status = PResolutionLevel::GetHistogram (alpha, red, green, blue, brightness, correctLut);
1099
1100 return status;
1101 }
1102
1103
1104 // ----------------------------------------------------------------------------
GetResolutionSizeInfo(int * width,int * height,int * nbTilesWidth,int * nbTilesHeight)1105 FPXStatus PResolutionFlashPix::GetResolutionSizeInfo (int* width, int* height, int* nbTilesWidth, int* nbTilesHeight)
1106 {
1107 FPXStatus status = FPX_OK;
1108
1109 // Read and allocate tile pointers if necessary
1110 if (!HasBeenUsed())
1111 status = UpdateHeaderStream();
1112
1113 // Call the parent method now
1114 if (status == 0)
1115 status = PResolutionLevel::GetResolutionSizeInfo (width, height, nbTilesWidth,
1116 nbTilesHeight);
1117
1118 return status;
1119 }
1120
1121
1122 // ----------------------------------------------------------------------------
ReadSampledRectangle(int x0,int y0,int x1,int y1,Pixel * map,short pixelsPerLine,int mapWidth,int mapHeight,Boolean showAlphaChannel,float ratio)1123 FPXStatus PResolutionFlashPix::ReadSampledRectangle(int x0, int y0, int x1, int y1, Pixel* map, short pixelsPerLine, int mapWidth, int mapHeight, Boolean showAlphaChannel, float ratio)
1124 {
1125 FPXStatus status = FPX_OK;
1126
1127 // Read and allocate tile pointers if necessary
1128 if (!HasBeenUsed())
1129 status = ReadHeaderStream();
1130
1131 // Call the parent method now
1132 if (status == FPX_OK)
1133 status = PResolutionLevel::ReadSampledRectangle (x0, y0, x1, y1, map, pixelsPerLine,
1134 mapWidth, mapHeight, showAlphaChannel, ratio);
1135 return status;
1136 }
1137
1138
1139 // ----------------------------------------------------------------------------
SearchPixelTopLeftCorner(int * x1,int * y1,float ratio)1140 FPXStatus PResolutionFlashPix::SearchPixelTopLeftCorner(int* x1, int* y1, float ratio)
1141 {
1142 FPXStatus status = FPX_OK;
1143
1144 // Read and allocate tile pointers if necessary
1145 if (!HasBeenUsed())
1146 status = UpdateHeaderStream();
1147
1148 // Call the parent method now
1149 if (status == FPX_OK)
1150 status = PResolutionLevel::SearchPixelTopLeftCorner (x1, y1, ratio);
1151
1152 return status;
1153 }
1154
1155
1156 // ----------------------------------------------------------------------------
1157 // Read a pixel of a sub image. Read it on disk if necessary.
1158 // If error, return false and pixel is set to 0.
ReadMean(int xi,int yi,Pixel & pixel)1159 FPXStatus PResolutionFlashPix::ReadMean (int xi, int yi, Pixel& pixel)
1160 {
1161 FPXStatus status = FPX_OK;
1162
1163 // Read and allocate tile pointers if necessary
1164 if (!HasBeenUsed())
1165 status = ReadHeaderStream();
1166
1167 // Call the parent method now
1168 if (status == FPX_OK)
1169 status = PResolutionLevel::ReadMean (xi, yi, pixel);
1170
1171 return status;
1172 }
1173
1174 // ----------------------------------------------------------------------------
1175 // External Functions
1176 // ----------------------------------------------------------------------------
1177
1178
1179
1180 // - EOF ----------------------------------------------------------------------
1181