private bool prettyPrintField(Stream fd, TiffTag tag, int value_count, object raw_data) { FieldValue value = new FieldValue(raw_data); short[] sdata = value.ToShortArray(); float[] fdata = value.ToFloatArray(); double[] ddata = value.ToDoubleArray(); switch (tag) { case TiffTag.InkSet: if (sdata != null) { fprintf(fd, " Ink Set: "); switch ((InkSet)sdata[0]) { case InkSet.CMYK: fprintf(fd, "CMYK\n"); break; default: fprintf(fd, "{0} (0x{1:x})\n", sdata[0], sdata[0]); break; } return true; } return false; case TiffTag.DotRange: if (sdata != null) { fprintf(fd, " Dot Range: {0}-{1}\n", sdata[0], sdata[1]); return true; } return false; case TiffTag.WhitePoint: if (fdata != null) { fprintf(fd, " White Point: {0:G}-{1:G}\n", fdata[0], fdata[1]); return true; } return false; case TiffTag.REFERENCEBLACKWHITE: if (fdata != null) { fprintf(fd, " Reference Black/White:\n"); for (short i = 0; i < 3; i++) fprintf(fd, " {0,2:D}: {1,5:G} {2,5:G}\n", i, fdata[2 * i + 0], fdata[2 * i + 1]); return true; } return false; case TiffTag.XMLPACKET: string s = raw_data as string; if (s != null) { fprintf(fd, " XMLPacket (XMP Metadata):\n"); fprintf(fd, s.Substring(0, value_count)); fprintf(fd, "\n"); return true; } return false; case TiffTag.RICHTIFFIPTC: // XXX: for some weird reason RichTIFFIPTC tag defined // as array of Long values. fprintf(fd, " RichTIFFIPTC Data: <present>, {0} bytes\n", value_count * 4); return true; case TiffTag.PHOTOSHOP: fprintf(fd, " Photoshop Data: <present>, {0} bytes\n", value_count); return true; case TiffTag.ICCPROFILE: fprintf(fd, " ICC Profile: <present>, {0} bytes\n", value_count); return true; case TiffTag.STONITS: if (ddata != null) { fprintf(fd, " Sample to Nits conversion factor: {0:e4}\n", ddata[0]); return true; } return false; } return false; }
/// <summary> /// Install extra samples information. /// </summary> private static bool setExtraSamples(TiffDirectory td, ref int v, FieldValue[] ap) { // XXX: Unassociated alpha data == 999 is a known Corel Draw bug, see below const short EXTRASAMPLE_COREL_UNASSALPHA = 999; v = ap[0].ToInt(); if (v > td.td_samplesperpixel) return false; byte[] va = ap[1].ToByteArray(); if (v > 0 && va == null) { // typically missing param return false; } for (int i = 0; i < v; i++) { if ((ExtraSample)va[i] > ExtraSample.UnAssociatedAlpha) { // XXX: Corel Draw is known to produce incorrect // ExtraSamples tags which must be patched here if we // want to be able to open some of the damaged TIFF files: if (i < v - 1) { short s = BitConverter.ToInt16(va, i); if (s == EXTRASAMPLE_COREL_UNASSALPHA) va[i] = (byte)ExtraSample.UnAssociatedAlpha; } else return false; } } td.td_extrasamples = (short)v; td.td_sampleinfo = new ExtraSample[td.td_extrasamples]; for (int i = 0; i < td.td_extrasamples; i++) td.td_sampleinfo[i] = (ExtraSample)va[i]; return true; }
/// <summary> /// Gets the value(s) of a tag in an open TIFF file or default value(s) of a tag if a tag /// is not defined in the current directory and it has a default value(s). /// </summary> /// <param name="tag">The tag.</param> /// <returns> /// The value(s) of a tag in an open TIFF file as array of /// <see cref="FieldValue"/> objects or <c>null</c> if there is no such tag set and /// tag has no default value. /// </returns> /// <remarks> /// <para> /// <see cref="GetFieldDefaulted"/> returns the value(s) of a tag or pseudo-tag associated /// with the current directory of the opened TIFF file or default value(s) of a tag if a /// tag is not defined in the current directory and it has a default value(s). The tag is /// identified by <paramref name="tag"/>. The type and number of values returned is /// dependent on the tag being requested. You may want to consult /// <a href="54cbd23d-dc55-44b9-921f-3a06efc2f6ce.htm">"Well-known tags and their /// value(s) data types"</a> to become familiar with exact data types and calling /// conventions required for each tag supported by the library. /// </para> /// <para> /// A pseudo-tag is a parameter that is used to control the operation of the library but /// whose value is not read or written to the underlying file. /// </para> /// </remarks> /// <seealso cref="GetField"/> public FieldValue[] GetFieldDefaulted(TiffTag tag) { TiffDirectory td = m_dir; FieldValue[] result = GetField(tag); if (result != null) return result; switch (tag) { case TiffTag.SubFileType: result = new FieldValue[1]; result[0].Set(td.td_subfiletype); break; case TiffTag.BitsPerSample: result = new FieldValue[1]; result[0].Set(td.td_bitspersample); break; case TiffTag.Threshholding: result = new FieldValue[1]; result[0].Set(td.td_threshholding); break; case TiffTag.FillOrder: result = new FieldValue[1]; result[0].Set(td.td_fillorder); break; case TiffTag.Orientation: result = new FieldValue[1]; result[0].Set(td.td_orientation); break; case TiffTag.SamplesPerPixel: result = new FieldValue[1]; result[0].Set(td.td_samplesperpixel); break; case TiffTag.RowsPerStrip: result = new FieldValue[1]; result[0].Set(td.td_rowsperstrip); break; case TiffTag.MinSampleValue: result = new FieldValue[1]; result[0].Set(td.td_minsamplevalue); break; case TiffTag.MaxSampleValue: result = new FieldValue[1]; result[0].Set(td.td_maxsamplevalue); break; case TiffTag.PlanarConfig: result = new FieldValue[1]; result[0].Set(td.td_planarconfig); break; case TiffTag.ResolutionUnit: result = new FieldValue[1]; result[0].Set(td.td_resolutionunit); break; case TiffTag.Predictor: CodecWithPredictor sp = m_currentCodec as CodecWithPredictor; if (sp != null) { result = new FieldValue[1]; result[0].Set(sp.GetPredictorValue()); } break; case TiffTag.DotRange: result = new FieldValue[2]; result[0].Set(0); result[1].Set((1 << td.td_bitspersample) - 1); break; case TiffTag.InkSet: result = new FieldValue[1]; result[0].Set(InkSet.CMYK); break; case TiffTag.NumberOfInks: result = new FieldValue[1]; result[0].Set(4); break; case TiffTag.ExtraSamples: result = new FieldValue[2]; result[0].Set(td.td_extrasamples); result[1].Set(td.td_sampleinfo); break; case TiffTag.MATTEING: result = new FieldValue[1]; result[0].Set((td.td_extrasamples == 1 && td.td_sampleinfo[0] == ExtraSample.AssociatedAlpha)); break; case TiffTag.TILEDEPTH: result = new FieldValue[1]; result[0].Set(td.td_tiledepth); break; case TiffTag.DATATYPE: result = new FieldValue[1]; result[0].Set(td.td_sampleformat - 1); break; case TiffTag.SampleFormat: result = new FieldValue[1]; result[0].Set(td.td_sampleformat); break; case TiffTag.IMAGEDEPTH: result = new FieldValue[1]; result[0].Set(td.td_imagedepth); break; case TiffTag.YCBCRCOEFFICIENTS: { // defaults are from CCIR Recommendation 601-1 float[] ycbcrcoeffs = new float[3]; ycbcrcoeffs[0] = 0.299f; ycbcrcoeffs[1] = 0.587f; ycbcrcoeffs[2] = 0.114f; result = new FieldValue[1]; result[0].Set(ycbcrcoeffs); break; } case TiffTag.YCBCRSUBSAMPLING: result = new FieldValue[2]; result[0].Set(td.td_ycbcrsubsampling[0]); result[1].Set(td.td_ycbcrsubsampling[1]); break; case TiffTag.YCBCRPOSITIONING: result = new FieldValue[1]; result[0].Set(td.td_ycbcrpositioning); break; case TiffTag.WhitePoint: { // TIFF 6.0 specification tells that it is no default value for the // WhitePoint, but AdobePhotoshop TIFF Technical Note tells that it // should be CIE D50. float[] whitepoint = new float[2]; whitepoint[0] = D50_X0 / (D50_X0 + D50_Y0 + D50_Z0); whitepoint[1] = D50_Y0 / (D50_X0 + D50_Y0 + D50_Z0); result = new FieldValue[1]; result[0].Set(whitepoint); break; } case TiffTag.TransferFunction: if (td.td_transferfunction[0] == null && !defaultTransferFunction(td)) { ErrorExt(this, m_clientdata, m_name, "No space for \"TransferFunction\" tag"); return null; } result = new FieldValue[3]; result[0].Set(td.td_transferfunction[0]); if (td.td_samplesperpixel - td.td_extrasamples > 1) { result[1].Set(td.td_transferfunction[1]); result[2].Set(td.td_transferfunction[2]); } break; case TiffTag.REFERENCEBLACKWHITE: if (td.td_refblackwhite == null) defaultRefBlackWhite(td); result = new FieldValue[1]; result[0].Set(td.td_refblackwhite); break; } return result; }
/// <summary> /// Sets the value(s) of a tag in a TIFF file/stream open for writing. /// </summary> /// <param name="tif">An instance of the <see cref="Tiff"/> class.</param> /// <param name="tag">The tag.</param> /// <param name="value">The tag value(s).</param> /// <returns> /// <c>true</c> if tag value(s) were set successfully; otherwise, <c>false</c>. /// </returns> /// <seealso cref="Tiff.SetField"/> public virtual bool SetField(Tiff tif, TiffTag tag, FieldValue[] value) { const string module = "vsetfield"; TiffDirectory td = tif.m_dir; bool status = true; int v32 = 0; int v = 0; bool end = false; bool badvalue = false; bool badvalue32 = false; switch (tag) { case TiffTag.SubFileType: td.td_subfiletype = (FileType)value[0].ToByte(); break; case TiffTag.ImageWidth: td.td_imagewidth = value[0].ToInt(); break; case TiffTag.ImageLength: td.td_imagelength = value[0].ToInt(); break; case TiffTag.BitsPerSample: td.td_bitspersample = value[0].ToShort(); // If the data require post-decoding processing to byte-swap samples, set it // up here. Note that since tags are required to be ordered, compression code // can override this behavior in the setup method if it wants to roll the post // decoding work in with its normal work. if ((tif.m_flags & TiffFlags.Swab) == TiffFlags.Swab) { if (td.td_bitspersample == 16) tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab16Bit; else if (td.td_bitspersample == 24) tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab24Bit; else if (td.td_bitspersample == 32) tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab32Bit; else if (td.td_bitspersample == 64) tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab64Bit; else if (td.td_bitspersample == 128) { // two 64's tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab64Bit; } } break; case TiffTag.Compression: v = value[0].ToInt() & 0xffff; Compression comp = (Compression)v; // If we're changing the compression scheme, then notify the previous module // so that it can cleanup any state it's setup. if (tif.fieldSet(FieldBit.Compression)) { if (td.td_compression == comp) break; tif.m_currentCodec.Cleanup(); tif.m_flags &= ~TiffFlags.CoderSetup; } // Setup new compression scheme. status = tif.setCompressionScheme(comp); if (status) td.td_compression = comp; else status = false; break; case TiffTag.Photometric: td.td_photometric = (Photometric)value[0].ToInt(); break; case TiffTag.Threshholding: td.td_threshholding = (Threshold)value[0].ToByte(); break; case TiffTag.FillOrder: v = value[0].ToInt(); BitOrder fo = (BitOrder)v; if (fo != BitOrder.LittleEndian && fo != BitOrder.BigEndian) { badvalue = true; break; } td.td_fillorder = fo; break; case TiffTag.Orientation: v = value[0].ToInt(); Orientation or = (Orientation)v; if (or < Orientation.TopLeft || Orientation.LeftBottom < or) { badvalue = true; break; } else td.td_orientation = or; break; case TiffTag.SamplesPerPixel: // XXX should cross check - e.g. if pallette, then 1 v = value[0].ToInt(); if (v == 0) { badvalue = true; break; } td.td_samplesperpixel = (short)v; break; case TiffTag.RowsPerStrip: v32 = value[0].ToInt(); if (v32 == 0) { badvalue32 = true; break; } td.td_rowsperstrip = v32; if (!tif.fieldSet(FieldBit.TileDimensions)) { td.td_tilelength = v32; td.td_tilewidth = td.td_imagewidth; } break; case TiffTag.MinSampleValue: td.td_minsamplevalue = value[0].ToShort(); break; case TiffTag.MaxSampleValue: td.td_maxsamplevalue = value[0].ToShort(); break; case TiffTag.SMinSampleValue: td.td_sminsamplevalue = value[0].ToDouble(); break; case TiffTag.SMaxSampleValue: td.td_smaxsamplevalue = value[0].ToDouble(); break; case TiffTag.XResolution: td.td_xresolution = value[0].ToFloat(); break; case TiffTag.YResolution: td.td_yresolution = value[0].ToFloat(); break; case TiffTag.PlanarConfig: v = value[0].ToInt(); PlanarConfig pc = (PlanarConfig)v; if (pc != PlanarConfig.Contig && pc != PlanarConfig.Separate) { badvalue = true; break; } td.td_planarconfig = pc; break; case TiffTag.XPosition: td.td_xposition = value[0].ToFloat(); break; case TiffTag.YPosition: td.td_yposition = value[0].ToFloat(); break; case TiffTag.ResolutionUnit: v = value[0].ToInt(); ResolutionUnit ru = (ResolutionUnit)v; if (ru < ResolutionUnit.None || ResolutionUnit.Centimeter < ru) { badvalue = true; break; } td.td_resolutionunit = ru; break; case TiffTag.PageNumber: td.td_pagenumber[0] = value[0].ToShort(); td.td_pagenumber[1] = value[1].ToShort(); break; case TiffTag.HalfToneHints: td.td_halftonehints[0] = value[0].ToShort(); td.td_halftonehints[1] = value[1].ToShort(); break; case TiffTag.Colormap: v32 = 1 << td.td_bitspersample; Tiff.setShortArray(out td.td_colormap[0], value[0].ToShortArray(), v32); Tiff.setShortArray(out td.td_colormap[1], value[1].ToShortArray(), v32); Tiff.setShortArray(out td.td_colormap[2], value[2].ToShortArray(), v32); break; case TiffTag.ExtraSamples: if (!setExtraSamples(td, ref v, value)) { badvalue = true; break; } break; case TiffTag.MATTEING: if (value[0].ToShort() != 0) td.td_extrasamples = 1; else td.td_extrasamples = 0; if (td.td_extrasamples != 0) { td.td_sampleinfo = new ExtraSample[1]; td.td_sampleinfo[0] = ExtraSample.AssociatedAlpha; } break; case TiffTag.TileWidth: v32 = value[0].ToInt(); if ((v32 % 16) != 0) { if (tif.m_mode != Tiff.O_RDONLY) { badvalue32 = true; break; } Tiff.WarningExt(tif, tif.m_clientdata, tif.m_name, "Nonstandard tile width {0}, convert file", v32); } td.td_tilewidth = v32; tif.m_flags |= TiffFlags.IsTiled; break; case TiffTag.TileLength: v32 = value[0].ToInt(); if ((v32 % 16) != 0) { if (tif.m_mode != Tiff.O_RDONLY) { badvalue32 = true; break; } Tiff.WarningExt(tif, tif.m_clientdata, tif.m_name, "Nonstandard tile length {0}, convert file", v32); } td.td_tilelength = v32; tif.m_flags |= TiffFlags.IsTiled; break; case TiffTag.TILEDEPTH: v32 = value[0].ToInt(); if (v32 == 0) { badvalue32 = true; break; } td.td_tiledepth = v32; break; case TiffTag.DATATYPE: v = value[0].ToInt(); SampleFormat sf = SampleFormat.UnTyped; switch (v) { case DATATYPE_VOID: sf = SampleFormat.UnTyped; break; case DATATYPE_INT: sf = SampleFormat.Int; break; case DATATYPE_UINT: sf = SampleFormat.UInt; break; case DATATYPE_IEEEFP: sf = SampleFormat.IEEEFloat; break; default: badvalue = true; break; } if (!badvalue) td.td_sampleformat = sf; break; case TiffTag.SampleFormat: v = value[0].ToInt(); sf = (SampleFormat)v; if (sf < SampleFormat.UInt || SampleFormat.ComplexIEEEFloat < sf) { badvalue = true; break; } td.td_sampleformat = sf; // Try to fix up the Swab function for complex data. if (td.td_sampleformat == SampleFormat.COMPLEXINT && td.td_bitspersample == 32 && tif.m_postDecodeMethod == Tiff.PostDecodeMethodType.pdmSwab32Bit) { tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab16Bit; } else if ((td.td_sampleformat == SampleFormat.COMPLEXINT || td.td_sampleformat == SampleFormat.ComplexIEEEFloat) && td.td_bitspersample == 64 && tif.m_postDecodeMethod == Tiff.PostDecodeMethodType.pdmSwab64Bit) { tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab32Bit; } break; case TiffTag.IMAGEDEPTH: td.td_imagedepth = value[0].ToInt(); break; case TiffTag.SubImageDescriptor: if ((tif.m_flags & TiffFlags.InSubIFD) != TiffFlags.InSubIFD) { td.td_nsubifd = value[0].ToShort(); Tiff.setLongArray(out td.td_subifd, value[1].ToIntArray(), td.td_nsubifd); } else { Tiff.ErrorExt(tif, tif.m_clientdata, module, "{0}: Sorry, cannot nest SubIFDs", tif.m_name); status = false; } break; case TiffTag.YCBCRPOSITIONING: td.td_ycbcrpositioning = (YCbCrPosition)value[0].ToByte(); break; case TiffTag.YCBCRSUBSAMPLING: td.td_ycbcrsubsampling[0] = value[0].ToShort(); td.td_ycbcrsubsampling[1] = value[1].ToShort(); break; case TiffTag.TransferFunction: v = ((td.td_samplesperpixel - td.td_extrasamples) > 1 ? 3 : 1); for (int i = 0; i < v; i++) { Tiff.setShortArray(out td.td_transferfunction[i], value[0].ToShortArray(), 1 << td.td_bitspersample); } break; case TiffTag.REFERENCEBLACKWHITE: // XXX should check for null range Tiff.setFloatArray(out td.td_refblackwhite, value[0].ToFloatArray(), 6); break; case TiffTag.InkNames: v = value[0].ToInt(); string s = value[1].ToString(); v = checkInkNamesString(tif, v, s); status = v > 0; if (v > 0) { setNString(out td.td_inknames, s, v); td.td_inknameslen = v; } break; default: // This can happen if multiple images are open with // different codecs which have private tags. The global tag // information table may then have tags that are valid for // one file but not the other. If the client tries to set a // tag that is not valid for the image's codec then we'll // arrive here. This happens, for example, when tiffcp is // used to convert between compression schemes and // codec-specific tags are blindly copied. TiffFieldInfo fip = tif.FindFieldInfo(tag, TiffType.Any); if (fip == null || fip.Bit != FieldBit.Custom) { Tiff.ErrorExt(tif, tif.m_clientdata, module, "{0}: Invalid {1}tag \"{2}\" (not supported by codec)", tif.m_name, Tiff.isPseudoTag(tag) ? "pseudo-" : "", fip != null ? fip.Name : "Unknown"); status = false; break; } // Find the existing entry for this custom value. int tvIndex = -1; for (int iCustom = 0; iCustom < td.td_customValueCount; iCustom++) { if (td.td_customValues[iCustom].info.Tag == tag) { td.td_customValues[iCustom].value = null; break; } } // Grow the custom list if the entry was not found. if (tvIndex == -1) { td.td_customValueCount++; TiffTagValue[] new_customValues = Tiff.Realloc( td.td_customValues, td.td_customValueCount - 1, td.td_customValueCount); td.td_customValues = new_customValues; tvIndex = td.td_customValueCount - 1; td.td_customValues[tvIndex].info = fip; td.td_customValues[tvIndex].value = null; td.td_customValues[tvIndex].count = 0; } // Set custom value ... save a copy of the custom tag value. int tv_size = Tiff.dataSize(fip.Type); if (tv_size == 0) { status = false; Tiff.ErrorExt(tif, tif.m_clientdata, module, "{0}: Bad field type {1} for \"{2}\"", tif.m_name, fip.Type, fip.Name); end = true; break; } int paramIndex = 0; if (fip.PassCount) { if (fip.WriteCount == TiffFieldInfo.Variable2) td.td_customValues[tvIndex].count = value[paramIndex++].ToInt(); else td.td_customValues[tvIndex].count = value[paramIndex++].ToInt(); } else if (fip.WriteCount == TiffFieldInfo.Variable || fip.WriteCount == TiffFieldInfo.Variable2) { td.td_customValues[tvIndex].count = 1; } else if (fip.WriteCount == TiffFieldInfo.Spp) { td.td_customValues[tvIndex].count = td.td_samplesperpixel; } else { td.td_customValues[tvIndex].count = fip.WriteCount; } if (fip.Type == TiffType.ASCII) { string ascii; Tiff.setString(out ascii, value[paramIndex++].ToString()); td.td_customValues[tvIndex].value = Tiff.Latin1Encoding.GetBytes(ascii); } else { td.td_customValues[tvIndex].value = new byte[tv_size * td.td_customValues[tvIndex].count]; if ((fip.PassCount || fip.WriteCount == TiffFieldInfo.Variable || fip.WriteCount == TiffFieldInfo.Variable2 || fip.WriteCount == TiffFieldInfo.Spp || td.td_customValues[tvIndex].count > 1) && fip.Tag != TiffTag.PageNumber && fip.Tag != TiffTag.HalfToneHints && fip.Tag != TiffTag.YCBCRSUBSAMPLING && fip.Tag != TiffTag.DotRange) { byte[] apBytes = value[paramIndex++].GetBytes(); //Buffer.BlockCopy(apBytes, 0, td.td_customValues[tvIndex].value, 0, apBytes.Length); Buffer.BlockCopy(apBytes, 0, td.td_customValues[tvIndex].value, 0, td.td_customValues[tvIndex].value.Length); } else { // XXX: The following loop required to handle // PageNumber, HalfToneHints, // YCBCRSUBSAMPLING and DotRange tags. // These tags are actually arrays and should be // passed as arrays to SetField() function, but // actually passed as a list of separate values. // This behavior must be changed in the future! // Upd: This loop also processes some EXIF tags with // Undefined type (like EXIF_FILESOURCE or EXIF_SCENETYPE) // In this case input value is string-based, so // in TiffType.Undefined case we use FieldValue.GetBytes()[0] // construction instead of direct call of FieldValue.ToByte() method. byte[] val = td.td_customValues[tvIndex].value; int valPos = 0; for (int i = 0; i < td.td_customValues[tvIndex].count; i++, valPos += tv_size) { switch (fip.Type) { case TiffType.Byte: case TiffType.Undefined: val[valPos] = value[paramIndex + i].GetBytes()[0]; break; case TiffType.SByte: val[valPos] = value[paramIndex + i].ToByte(); break; case TiffType.Short: Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToShort()), 0, val, valPos, tv_size); break; case TiffType.SShort: Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToShort()), 0, val, valPos, tv_size); break; case TiffType.Long: case TiffType.IFD: Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToInt()), 0, val, valPos, tv_size); break; case TiffType.SLong: Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToInt()), 0, val, valPos, tv_size); break; case TiffType.Rational: case TiffType.SRational: case TiffType.Float: Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToFloat()), 0, val, valPos, tv_size); break; case TiffType.Double: Buffer.BlockCopy(BitConverter.GetBytes(value[paramIndex + i].ToDouble()), 0, val, valPos, tv_size); break; default: Array.Clear(val, valPos, tv_size); status = false; break; } } } } break; } if (!end && !badvalue && !badvalue32) { if (status) { tif.setFieldBit(tif.FieldWithTag(tag).Bit); tif.m_flags |= TiffFlags.DirtyDirect; } } if (badvalue) { Tiff.ErrorExt(tif, tif.m_clientdata, module, "{0}: Bad value {1} for \"{2}\" tag", tif.m_name, v, tif.FieldWithTag(tag).Name); return false; } if (badvalue32) { Tiff.ErrorExt(tif, tif.m_clientdata, module, "{0}: Bad value {1} for \"{2}\" tag", tif.m_name, v32, tif.FieldWithTag(tag).Name); return false; } return status; }
/// <summary> /// Gets the value(s) of a tag in an open TIFF file. /// </summary> /// <param name="tif">An instance of the <see cref="Tiff"/> class.</param> /// <param name="tag">The tag.</param> /// <returns>The value(s) of a tag in an open TIFF file/stream as array of /// <see cref="FieldValue"/> objects or <c>null</c> if there is no such tag set.</returns> /// <seealso cref="Tiff.GetField"/> public virtual FieldValue[] GetField(Tiff tif, TiffTag tag) { TiffDirectory td = tif.m_dir; FieldValue[] result = null; switch (tag) { case TiffTag.SubFileType: result = new FieldValue[1]; result[0].Set(td.td_subfiletype); break; case TiffTag.ImageWidth: result = new FieldValue[1]; result[0].Set(td.td_imagewidth); break; case TiffTag.ImageLength: result = new FieldValue[1]; result[0].Set(td.td_imagelength); break; case TiffTag.BitsPerSample: result = new FieldValue[1]; result[0].Set(td.td_bitspersample); break; case TiffTag.Compression: result = new FieldValue[1]; result[0].Set(td.td_compression); break; case TiffTag.Photometric: result = new FieldValue[1]; result[0].Set(td.td_photometric); break; case TiffTag.Threshholding: result = new FieldValue[1]; result[0].Set(td.td_threshholding); break; case TiffTag.FillOrder: result = new FieldValue[1]; result[0].Set(td.td_fillorder); break; case TiffTag.Orientation: result = new FieldValue[1]; result[0].Set(td.td_orientation); break; case TiffTag.SamplesPerPixel: result = new FieldValue[1]; result[0].Set(td.td_samplesperpixel); break; case TiffTag.RowsPerStrip: result = new FieldValue[1]; result[0].Set(td.td_rowsperstrip); break; case TiffTag.MinSampleValue: result = new FieldValue[1]; result[0].Set(td.td_minsamplevalue); break; case TiffTag.MaxSampleValue: result = new FieldValue[1]; result[0].Set(td.td_maxsamplevalue); break; case TiffTag.SMinSampleValue: result = new FieldValue[1]; result[0].Set(td.td_sminsamplevalue); break; case TiffTag.SMaxSampleValue: result = new FieldValue[1]; result[0].Set(td.td_smaxsamplevalue); break; case TiffTag.XResolution: result = new FieldValue[1]; result[0].Set(td.td_xresolution); break; case TiffTag.YResolution: result = new FieldValue[1]; result[0].Set(td.td_yresolution); break; case TiffTag.PlanarConfig: result = new FieldValue[1]; result[0].Set(td.td_planarconfig); break; case TiffTag.XPosition: result = new FieldValue[1]; result[0].Set(td.td_xposition); break; case TiffTag.YPosition: result = new FieldValue[1]; result[0].Set(td.td_yposition); break; case TiffTag.ResolutionUnit: result = new FieldValue[1]; result[0].Set(td.td_resolutionunit); break; case TiffTag.PageNumber: result = new FieldValue[2]; result[0].Set(td.td_pagenumber[0]); result[1].Set(td.td_pagenumber[1]); break; case TiffTag.HalfToneHints: result = new FieldValue[2]; result[0].Set(td.td_halftonehints[0]); result[1].Set(td.td_halftonehints[1]); break; case TiffTag.Colormap: result = new FieldValue[3]; result[0].Set(td.td_colormap[0]); result[1].Set(td.td_colormap[1]); result[2].Set(td.td_colormap[2]); break; case TiffTag.StripOffsets: case TiffTag.TileOffsets: result = new FieldValue[1]; result[0].Set(td.td_stripoffset); break; case TiffTag.StripByteCounts: case TiffTag.TileByteCounts: result = new FieldValue[1]; result[0].Set(td.td_stripbytecount); break; case TiffTag.MATTEING: result = new FieldValue[1]; result[0].Set((td.td_extrasamples == 1 && td.td_sampleinfo[0] == ExtraSample.AssociatedAlpha)); break; case TiffTag.ExtraSamples: result = new FieldValue[2]; result[0].Set(td.td_extrasamples); result[1].Set(td.td_sampleinfo); break; case TiffTag.TileWidth: result = new FieldValue[1]; result[0].Set(td.td_tilewidth); break; case TiffTag.TileLength: result = new FieldValue[1]; result[0].Set(td.td_tilelength); break; case TiffTag.TILEDEPTH: result = new FieldValue[1]; result[0].Set(td.td_tiledepth); break; case TiffTag.DATATYPE: switch (td.td_sampleformat) { case SampleFormat.UInt: result = new FieldValue[1]; result[0].Set(DATATYPE_UINT); break; case SampleFormat.Int: result = new FieldValue[1]; result[0].Set(DATATYPE_INT); break; case SampleFormat.IEEEFloat: result = new FieldValue[1]; result[0].Set(DATATYPE_IEEEFP); break; case SampleFormat.UnTyped: result = new FieldValue[1]; result[0].Set(DATATYPE_VOID); break; } break; case TiffTag.SampleFormat: result = new FieldValue[1]; result[0].Set(td.td_sampleformat); break; case TiffTag.IMAGEDEPTH: result = new FieldValue[1]; result[0].Set(td.td_imagedepth); break; case TiffTag.SubImageDescriptor: result = new FieldValue[2]; result[0].Set(td.td_nsubifd); result[1].Set(td.td_subifd); break; case TiffTag.YCBCRPOSITIONING: result = new FieldValue[1]; result[0].Set(td.td_ycbcrpositioning); break; case TiffTag.YCBCRSUBSAMPLING: result = new FieldValue[2]; result[0].Set(td.td_ycbcrsubsampling[0]); result[1].Set(td.td_ycbcrsubsampling[1]); break; case TiffTag.TransferFunction: result = new FieldValue[3]; result[0].Set(td.td_transferfunction[0]); if (td.td_samplesperpixel - td.td_extrasamples > 1) { result[1].Set(td.td_transferfunction[1]); result[2].Set(td.td_transferfunction[2]); } break; case TiffTag.REFERENCEBLACKWHITE: if (td.td_refblackwhite != null) { result = new FieldValue[1]; result[0].Set(td.td_refblackwhite); } break; case TiffTag.InkNames: result = new FieldValue[1]; result[0].Set(td.td_inknames); break; default: // This can happen if multiple images are open with // different codecs which have private tags. The global tag // information table may then have tags that are valid for // one file but not the other. If the client tries to get a // tag that is not valid for the image's codec then we'll // arrive here. TiffFieldInfo fip = tif.FindFieldInfo(tag, TiffType.Any); if (fip == null || fip.Bit != FieldBit.Custom) { Tiff.ErrorExt(tif, tif.m_clientdata, "_TIFFVGetField", "{0}: Invalid {1}tag \"{2}\" (not supported by codec)", tif.m_name, Tiff.isPseudoTag(tag) ? "pseudo-" : "", fip != null ? fip.Name : "Unknown"); result = null; break; } // Do we have a custom value? result = null; for (int i = 0; i < td.td_customValueCount; i++) { TiffTagValue tv = td.td_customValues[i]; if (tv.info.Tag != tag) continue; if (fip.PassCount) { result = new FieldValue[2]; if (fip.ReadCount == TiffFieldInfo.Variable2) { result[0].Set(tv.count); } else { // Assume TiffFieldInfo.Variable result[0].Set(tv.count); } result[1].Set(tv.value); } else { if ((fip.Type == TiffType.ASCII || fip.ReadCount == TiffFieldInfo.Variable || fip.ReadCount == TiffFieldInfo.Variable2 || fip.ReadCount == TiffFieldInfo.Spp || tv.count > 1) && fip.Tag != TiffTag.PageNumber && fip.Tag != TiffTag.HalfToneHints && fip.Tag != TiffTag.YCBCRSUBSAMPLING && fip.Tag != TiffTag.DotRange) { result = new FieldValue[1]; byte[] value = tv.value; if (fip.Type == TiffType.ASCII && tv.value.Length > 0 && tv.value[tv.value.Length - 1] == 0) { // cut unwanted zero at the end value = new byte[Math.Max(tv.value.Length - 1, 0)]; Buffer.BlockCopy(tv.value, 0, value, 0, value.Length); } result[0].Set(value); } else { result = new FieldValue[tv.count]; byte[] val = tv.value; int valPos = 0; for (int j = 0; j < tv.count; j++, valPos += Tiff.dataSize(tv.info.Type)) { switch (fip.Type) { case TiffType.Byte: case TiffType.Undefined: case TiffType.SByte: result[j].Set(val[valPos]); break; case TiffType.Short: case TiffType.SShort: result[j].Set(BitConverter.ToInt16(val, valPos)); break; case TiffType.Long: case TiffType.IFD: case TiffType.SLong: result[j].Set(BitConverter.ToInt32(val, valPos)); break; case TiffType.Rational: case TiffType.SRational: case TiffType.Float: result[j].Set(BitConverter.ToSingle(val, valPos)); break; case TiffType.Double: result[j].Set(BitConverter.ToDouble(val, valPos)); break; default: result = null; break; } } } } break; } break; } return result; }
public override bool SetField(Tiff tif, TiffTag tag, FieldValue[] ap) { const string module = "OJPEGVSetField"; OJpegCodec sp = tif.m_currentCodec as OJpegCodec; Debug.Assert(sp != null); uint ma; uint[] mb; uint n; switch (tag) { case TiffTag.JPEGIFOffset: sp.m_jpeg_interchange_format = ap[0].ToUInt(); break; case TiffTag.JPEGIFByteCount: sp.m_jpeg_interchange_format_length = ap[0].ToUInt(); break; case TiffTag.YCBCRSUBSAMPLING: sp.m_subsampling_tag = true; sp.m_subsampling_hor = ap[0].ToByte(); sp.m_subsampling_ver = ap[1].ToByte(); tif.m_dir.td_ycbcrsubsampling[0] = sp.m_subsampling_hor; tif.m_dir.td_ycbcrsubsampling[1] = sp.m_subsampling_ver; break; case TiffTag.JPEGQTables: ma = ap[0].ToUInt(); if (ma != 0) { if (ma > 3) { Tiff.ErrorExt(tif, tif.m_clientdata, module, "JpegQTables tag has incorrect count"); return false; } sp.m_qtable_offset_count = (byte)ma; mb = ap[1].ToUIntArray(); for (n = 0; n < ma; n++) sp.m_qtable_offset[n] = mb[n]; } break; case TiffTag.JPEGDCTables: ma = ap[0].ToUInt(); if (ma != 0) { if (ma > 3) { Tiff.ErrorExt(tif, tif.m_clientdata, module, "JpegDcTables tag has incorrect count"); return false; } sp.m_dctable_offset_count = (byte)ma; mb = ap[1].ToUIntArray(); for (n = 0; n < ma; n++) sp.m_dctable_offset[n] = mb[n]; } break; case TiffTag.JPEGACTABLES: ma = ap[0].ToUInt(); if (ma != 0) { if (ma > 3) { Tiff.ErrorExt(tif, tif.m_clientdata, module, "JpegAcTables tag has incorrect count"); return false; } sp.m_actable_offset_count = (byte)ma; mb = ap[1].ToUIntArray(); for (n = 0; n < ma; n++) sp.m_actable_offset[n] = mb[n]; } break; case TiffTag.JPEGProc: sp.m_jpeg_proc = ap[0].ToByte(); break; case TiffTag.JPEGRestartInterval: sp.m_restart_interval = ap[0].ToUShort(); break; default: return base.SetField(tif, tag, ap); } TiffFieldInfo fip = tif.FieldWithTag(tag); if (fip != null) tif.setFieldBit(fip.Bit); else return false; tif.m_flags |= TiffFlags.DirtyDirect; return true; }
public override FieldValue[] GetField(Tiff tif, TiffTag tag) { OJpegCodec sp = tif.m_currentCodec as OJpegCodec; Debug.Assert(sp != null); FieldValue[] result = null; switch (tag) { case TiffTag.JPEGIFOffset: result = new FieldValue[1]; result[0].Set(sp.m_jpeg_interchange_format); break; case TiffTag.JPEGIFByteCount: result = new FieldValue[1]; result[0].Set(sp.m_jpeg_interchange_format_length); break; case TiffTag.YCBCRSUBSAMPLING: if (!sp.m_subsamplingcorrect_done) sp.OJPEGSubsamplingCorrect(); result = new FieldValue[2]; result[0].Set(sp.m_subsampling_hor); result[1].Set(sp.m_subsampling_ver); break; case TiffTag.JPEGQTables: result = new FieldValue[2]; result[0].Set(sp.m_qtable_offset_count); result[1].Set(sp.m_qtable_offset); break; case TiffTag.JPEGDCTables: result = new FieldValue[2]; result[0].Set(sp.m_dctable_offset_count); result[1].Set(sp.m_dctable_offset); break; case TiffTag.JPEGACTABLES: result = new FieldValue[2]; result[0].Set(sp.m_actable_offset_count); result[1].Set(sp.m_actable_offset); break; case TiffTag.JPEGProc: result = new FieldValue[1]; result[0].Set(sp.m_jpeg_proc); break; case TiffTag.JPEGRestartInterval: result = new FieldValue[1]; result[0].Set(sp.m_restart_interval); break; default: return base.GetField(tif, tag); } return result; }
public override bool SetField(Tiff tif, TiffTag tag, FieldValue[] ap) { JpegCodec sp = tif.m_currentCodec as JpegCodec; Debug.Assert(sp != null); switch (tag) { case TiffTag.JpegTables: int v32 = ap[0].ToInt(); if (v32 == 0) { // XXX return false; } sp.m_jpegtables = new byte[v32]; Buffer.BlockCopy(ap[1].ToByteArray(), 0, sp.m_jpegtables, 0, v32); sp.m_jpegtables_length = v32; tif.setFieldBit(JpegCodec.FIELD_JPEGTABLES); break; case TiffTag.JPEGQUALITY: sp.m_jpegquality = ap[0].ToInt(); return true; // pseudo tag case TiffTag.JPEGCOLORMODE: sp.m_jpegcolormode = (JpegColorMode)ap[0].ToShort(); sp.JPEGResetUpsampled(); return true; // pseudo tag case TiffTag.Photometric: bool ret_value = base.SetField(tif, tag, ap); sp.JPEGResetUpsampled(); return ret_value; case TiffTag.JPEGTABLESMODE: sp.m_jpegtablesmode = (JpegTablesMode)ap[0].ToShort(); return true; // pseudo tag case TiffTag.YCBCRSUBSAMPLING: // mark the fact that we have a real ycbcrsubsampling! sp.m_ycbcrsampling_fetched = true; // should we be recomputing upsampling info here? return base.SetField(tif, tag, ap); case TiffTag.FAXRECVPARAMS: sp.m_recvparams = ap[0].ToInt(); break; case TiffTag.FAXSUBADDRESS: Tiff.setString(out sp.m_subaddress, ap[0].ToString()); break; case TiffTag.FAXRECVTIME: sp.m_recvtime = ap[0].ToInt(); break; case TiffTag.FAXDCS: Tiff.setString(out sp.m_faxdcs, ap[0].ToString()); break; default: return base.SetField(tif, tag, ap); } TiffFieldInfo fip = tif.FieldWithTag(tag); if (fip != null) tif.setFieldBit(fip.Bit); else return false; tif.m_flags |= TiffFlags.DirtyDirect; return true; }
public override FieldValue[] GetField(Tiff tif, TiffTag tag) { JpegCodec sp = tif.m_currentCodec as JpegCodec; Debug.Assert(sp != null); FieldValue[] result = null; switch (tag) { case TiffTag.JpegTables: result = new FieldValue[2]; result[0].Set(sp.m_jpegtables_length); result[1].Set(sp.m_jpegtables); break; case TiffTag.JPEGQUALITY: result = new FieldValue[1]; result[0].Set(sp.m_jpegquality); break; case TiffTag.JPEGCOLORMODE: result = new FieldValue[1]; result[0].Set(sp.m_jpegcolormode); break; case TiffTag.JPEGTABLESMODE: result = new FieldValue[1]; result[0].Set(sp.m_jpegtablesmode); break; case TiffTag.YCBCRSUBSAMPLING: JPEGFixupTestSubsampling(tif); return base.GetField(tif, tag); case TiffTag.FAXRECVPARAMS: result = new FieldValue[1]; result[0].Set(sp.m_recvparams); break; case TiffTag.FAXSUBADDRESS: result = new FieldValue[1]; result[0].Set(sp.m_subaddress); break; case TiffTag.FAXRECVTIME: result = new FieldValue[1]; result[0].Set(sp.m_recvtime); break; case TiffTag.FAXDCS: result = new FieldValue[1]; result[0].Set(sp.m_faxdcs); break; default: return base.GetField(tif, tag); } return result; }
public override FieldValue[] GetField(Tiff tif, TiffTag tag) { DeflateCodec sp = tif.m_currentCodec as DeflateCodec; Debug.Assert(sp != null); switch (tag) { case TiffTag.ZIPQUALITY: FieldValue[] result = new FieldValue[1]; result[0].Set(sp.m_zipquality); return result; } return base.GetField(tif, tag); }
static internal FieldValue[] FromParams(params object[] list) { FieldValue[] values = new FieldValue[list.Length]; for (int i = 0; i < list.Length; i++) { if (list[i] is FieldValue) values[i] = new FieldValue(((FieldValue)(list[i])).Value); else values[i] = new FieldValue(list[i]); } return values; }
public override bool SetField(Tiff tif, TiffTag tag, FieldValue[] ap) { DeflateCodec sp = tif.m_currentCodec as DeflateCodec; Debug.Assert(sp != null); const string module = "ZIPVSetField"; switch (tag) { case TiffTag.ZIPQUALITY: sp.m_zipquality = ap[0].ToInt(); if ((sp.m_state & DeflateCodec.ZSTATE_INIT_ENCODE) != 0) { if (sp.m_stream.deflateParams(sp.m_zipquality, zlibConst.Z_DEFAULT_STRATEGY) != zlibConst.Z_OK) { Tiff.ErrorExt(tif, tif.m_clientdata, module, "{0}: zlib error: {0}", tif.m_name, sp.m_stream.msg); return false; } } return true; } return base.SetField(tif, tag, ap); }
public override FieldValue[] GetField(Tiff tif, TiffTag tag) { CodecWithPredictor sp = tif.m_currentCodec as CodecWithPredictor; Debug.Assert(sp != null); switch (tag) { case TiffTag.Predictor: FieldValue[] result = new FieldValue[1]; result[0].Set(sp.GetPredictorValue()); return result; } TiffTagMethods childMethods = sp.GetChildTagMethods(); if (childMethods != null) return childMethods.GetField(tif, tag); return base.GetField(tif, tag); }
public override bool SetField(Tiff tif, TiffTag tag, FieldValue[] ap) { CodecWithPredictor sp = tif.m_currentCodec as CodecWithPredictor; Debug.Assert(sp != null); switch (tag) { case TiffTag.Predictor: sp.SetPredictorValue((PredictionScheme)ap[0].ToByte()); tif.setFieldBit(CodecWithPredictor.FIELD_PREDICTOR); tif.m_flags |= TiffFlags.DirtyDirect; return true; } TiffTagMethods childMethods = sp.GetChildTagMethods(); if (childMethods != null) return childMethods.SetField(tif, tag, ap); return base.SetField(tif, tag, ap); }
public override FieldValue[] GetField(Tiff tif, TiffTag tag) { CCITTCodec sp = tif.m_currentCodec as CCITTCodec; Debug.Assert(sp != null); FieldValue[] result = new FieldValue[1]; switch (tag) { case TiffTag.FAXMODE: result[0].Set(sp.m_mode); break; case TiffTag.FAXFILLFUNC: result[0].Set(sp.fill); break; case TiffTag.Group3Options: case TiffTag.Group4Options: result[0].Set(sp.m_groupoptions); break; case TiffTag.BadFaxLines: result[0].Set(sp.m_badfaxlines); break; case TiffTag.CleanFaxData: result[0].Set(sp.m_cleanfaxdata); break; case TiffTag.ConsecutiveBadFaxLines: result[0].Set(sp.m_badfaxrun); break; case TiffTag.FAXRECVPARAMS: result[0].Set(sp.m_recvparams); break; case TiffTag.FAXSUBADDRESS: result[0].Set(sp.m_subaddress); break; case TiffTag.FAXRECVTIME: result[0].Set(sp.m_recvtime); break; case TiffTag.FAXDCS: result[0].Set(sp.m_faxdcs); break; default: return base.GetField(tif, tag); } return result; }
public override bool SetField(Tiff tif, TiffTag tag, FieldValue[] ap) { CCITTCodec sp = tif.m_currentCodec as CCITTCodec; Debug.Assert(sp != null); switch (tag) { case TiffTag.FAXMODE: sp.m_mode = (FaxMode)ap[0].ToShort(); return true; /* NB: pseudo tag */ case TiffTag.FAXFILLFUNC: sp.fill = ap[0].Value as Tiff.FaxFillFunc; return true; /* NB: pseudo tag */ case TiffTag.Group3Options: /* XXX: avoid reading options if compression mismatches. */ if (tif.m_dir.td_compression == Compression.CCITTFAX3) sp.m_groupoptions = (Group3Option)ap[0].ToShort(); break; case TiffTag.Group4Options: /* XXX: avoid reading options if compression mismatches. */ if (tif.m_dir.td_compression == Compression.CCITTFAX4) sp.m_groupoptions = (Group3Option)ap[0].ToShort(); break; case TiffTag.BadFaxLines: sp.m_badfaxlines = ap[0].ToInt(); break; case TiffTag.CleanFaxData: sp.m_cleanfaxdata = (CleanFaxData)ap[0].ToByte(); break; case TiffTag.ConsecutiveBadFaxLines: sp.m_badfaxrun = ap[0].ToInt(); break; case TiffTag.FAXRECVPARAMS: sp.m_recvparams = ap[0].ToInt(); break; case TiffTag.FAXSUBADDRESS: Tiff.setString(out sp.m_subaddress, ap[0].ToString()); break; case TiffTag.FAXRECVTIME: sp.m_recvtime = ap[0].ToInt(); break; case TiffTag.FAXDCS: Tiff.setString(out sp.m_faxdcs, ap[0].ToString()); break; default: return base.SetField(tif, tag, ap); } TiffFieldInfo fip = tif.FieldWithTag(tag); if (fip != null) tif.setFieldBit(fip.Bit); else return false; tif.m_flags |= TiffFlags.DirtyDirect; return true; }