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; }
/// <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.ASSOCALPHA)); 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> /// 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.ASSOCALPHA)); 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.IEEEFP: result = new FieldValue[1]; result[0].Set(DATATYPE_IEEEFP); break; case SampleFormat.VOID: 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.SUBIFD: 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-" : string.Empty, 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); }
/// <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.UNASSALPHA) { // 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.UNASSALPHA; } 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. /// </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.ASSOCALPHA)); 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.IEEEFP: result = new FieldValue[1]; result[0].Set(DATATYPE_IEEEFP); break; case SampleFormat.VOID: 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.SUBIFD: 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-" : string.Empty, 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; }
/// <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) { switch (td.td_bitspersample) { case 16: tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab16Bit; break; case 24: tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab24Bit; break; case 32: tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab32Bit; break; case 64: tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab64Bit; break; case 128: // two 64's tif.m_postDecodeMethod = Tiff.PostDecodeMethodType.pdmSwab64Bit; break; } } 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(); FillOrder fo = (FillOrder)v; if (fo != FillOrder.LSB2MSB && fo != FillOrder.MSB2LSB) { badvalue = true; break; } td.td_fillorder = fo; break; case TiffTag.ORIENTATION: v = value[0].ToInt(); Orientation or = (Orientation)v; if (or < Orientation.TOPLEFT || Orientation.LEFTBOT < 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].ToUShort(); break; case TiffTag.MAXSAMPLEVALUE: td.td_maxsamplevalue = value[0].ToUShort(); 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(); ResUnit ru = (ResUnit)v; if (ru < ResUnit.NONE || ResUnit.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.ASSOCALPHA; } 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.VOID; switch (v) { case DATATYPE_VOID: sf = SampleFormat.VOID; break; case DATATYPE_INT: sf = SampleFormat.INT; break; case DATATYPE_UINT: sf = SampleFormat.UINT; break; case DATATYPE_IEEEFP: sf = SampleFormat.IEEEFP; 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.COMPLEXIEEEFP < 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.COMPLEXIEEEFP) && 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.SUBIFD: if ((tif.m_flags & TiffFlags.INSUBIFD) != TiffFlags.INSUBIFD) { td.td_nsubifd = value[0].ToInt(); Tiff.setLong8Array(out td.td_subifd, value[1].TolongArray(), 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].ToShort(); 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-" : string.Empty, 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) { tvIndex = iCustom; 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, Math.Min(apBytes.Length, 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; }
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); }
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; }