示例#1
0
        private static Dictionary <MetadataSection, Dictionary <ushort, MetadataEntry> > CreateTagDictionary(
            Document doc,
            IDictionary <MetadataKey, MetadataEntry> entries,
            ExifColorSpace exifColorSpace)
        {
            Dictionary <MetadataSection, Dictionary <ushort, MetadataEntry> > metadataEntries = new Dictionary <MetadataSection, Dictionary <ushort, MetadataEntry> >
            {
                {
                    MetadataSection.Image,
                    new Dictionary <ushort, MetadataEntry>
                    {
                        {
                            MetadataKeys.Image.Orientation.TagId,
                            new MetadataEntry(MetadataKeys.Image.Orientation,
                                              TagDataType.Short,
                                              MetadataHelpers.EncodeShort(TiffConstants.Orientation.TopLeft))
                        }
                    }
                },
                {
                    MetadataSection.Exif,
                    new Dictionary <ushort, MetadataEntry>()
                }
            };

            // Add the image size tags.
            if (IsUncompressedImage(entries))
            {
                Dictionary <ushort, MetadataEntry> imageSection = metadataEntries[MetadataSection.Image];
                imageSection.Add(MetadataKeys.Image.ImageWidth.TagId,
                                 new MetadataEntry(MetadataKeys.Image.ImageWidth,
                                                   TagDataType.Long,
                                                   MetadataHelpers.EncodeLong((uint)doc.Width)));
                imageSection.Add(MetadataKeys.Image.ImageLength.TagId,
                                 new MetadataEntry(MetadataKeys.Image.ImageLength,
                                                   TagDataType.Long,
                                                   MetadataHelpers.EncodeLong((uint)doc.Height)));

                entries.Remove(MetadataKeys.Image.ImageWidth);
                entries.Remove(MetadataKeys.Image.ImageLength);
                // These tags should not be included in uncompressed images.
                entries.Remove(MetadataKeys.Exif.PixelXDimension);
                entries.Remove(MetadataKeys.Exif.PixelYDimension);
            }
            else
            {
                Dictionary <ushort, MetadataEntry> exifSection = metadataEntries[MetadataSection.Exif];
                exifSection.Add(MetadataKeys.Exif.PixelXDimension.TagId,
                                new MetadataEntry(MetadataKeys.Exif.PixelXDimension,
                                                  TagDataType.Long,
                                                  MetadataHelpers.EncodeLong((uint)doc.Width)));
                exifSection.Add(MetadataKeys.Exif.PixelYDimension.TagId,
                                new MetadataEntry(MetadataKeys.Exif.PixelYDimension,
                                                  TagDataType.Long,
                                                  MetadataHelpers.EncodeLong((uint)doc.Height)));

                entries.Remove(MetadataKeys.Exif.PixelXDimension);
                entries.Remove(MetadataKeys.Exif.PixelYDimension);
                // These tags should not be included in compressed images.
                entries.Remove(MetadataKeys.Image.ImageWidth);
                entries.Remove(MetadataKeys.Image.ImageLength);
            }

            // Add the EXIF color space tag.
            if (!entries.ContainsKey(MetadataKeys.Exif.ColorSpace))
            {
                metadataEntries[MetadataSection.Exif].Add(MetadataKeys.Exif.ColorSpace.TagId,
                                                          new MetadataEntry(MetadataKeys.Exif.ColorSpace,
                                                                            TagDataType.Short,
                                                                            MetadataHelpers.EncodeShort((ushort)exifColorSpace)));
            }

            foreach (KeyValuePair <MetadataKey, MetadataEntry> kvp in entries)
            {
                MetadataEntry entry = kvp.Value;

                MetadataSection section = entry.Section;

                if (section == MetadataSection.Image && !ExifTagHelper.CanWriteImageSectionTag(entry.TagId))
                {
                    continue;
                }

                if (metadataEntries.TryGetValue(section, out Dictionary <ushort, MetadataEntry> values))
                {
                    if (!values.ContainsKey(entry.TagId))
                    {
                        values.Add(entry.TagId, entry);
                    }
                }
                else
                {
                    metadataEntries.Add(section, new Dictionary <ushort, MetadataEntry>
                    {
                        { entry.TagId, entry }
                    });
                }
            }

            AddVersionEntries(ref metadataEntries);

            return(metadataEntries);
        }
示例#2
0
        private static IFDEntryInfo CreateIFDList(Dictionary <ushort, MetadataEntry> tags, long startOffset)
        {
            List <IFDEntry> ifdEntries = new List <IFDEntry>(tags.Count);

            // Leave room for the tag count, tags and next IFD offset.
            long ifdDataOffset = startOffset + sizeof(ushort) + ((long)tags.Count * IFDEntry.SizeOf) + sizeof(uint);

            foreach (KeyValuePair <ushort, MetadataEntry> item in tags.OrderBy(i => i.Key))
            {
                MetadataEntry entry = item.Value;

                uint count;
                switch (entry.Type)
                {
                case TagDataType.Byte:
                case TagDataType.Ascii:
                case TagDataType.SByte:
                case TagDataType.Undefined:
                    count = (uint)entry.LengthInBytes;
                    break;

                case TagDataType.Short:
                case TagDataType.SShort:
                    count = (uint)entry.LengthInBytes / 2;
                    break;

                case TagDataType.Long:
                case TagDataType.SLong:
                case TagDataType.Float:
                    count = (uint)entry.LengthInBytes / 4;
                    break;

                case TagDataType.Rational:
                case TagDataType.SRational:
                case TagDataType.Double:
                    count = (uint)entry.LengthInBytes / 8;
                    break;

                default:
                    throw new InvalidOperationException("Unexpected tag type.");
                }

                if (TagDataTypeUtil.ValueFitsInOffsetField(entry.Type, count))
                {
                    uint packedOffset = 0;

                    // Some applications may write EXIF fields with a count of zero.
                    // See https://github.com/0xC0000054/pdn-webp/issues/6.
                    if (count > 0)
                    {
                        byte[] data = entry.GetDataReadOnly();

                        // The data is always in little-endian byte order.
                        switch (data.Length)
                        {
                        case 1:
                            packedOffset |= data[0];
                            break;

                        case 2:
                            packedOffset |= data[0];
                            packedOffset |= (uint)data[1] << 8;
                            break;

                        case 3:
                            packedOffset |= data[0];
                            packedOffset |= (uint)data[1] << 8;
                            packedOffset |= (uint)data[2] << 16;
                            break;

                        case 4:
                            packedOffset |= data[0];
                            packedOffset |= (uint)data[1] << 8;
                            packedOffset |= (uint)data[2] << 16;
                            packedOffset |= (uint)data[3] << 24;
                            break;

                        default:
                            throw new InvalidOperationException("data.Length must be in the range of [1-4].");
                        }
                    }

                    ifdEntries.Add(new IFDEntry(entry.TagId, entry.Type, count, packedOffset));
                }
                else
                {
                    ifdEntries.Add(new IFDEntry(entry.TagId, entry.Type, count, (uint)ifdDataOffset));
                    ifdDataOffset += entry.LengthInBytes;

                    // The IFD offsets must begin on a WORD boundary.
                    if ((ifdDataOffset & 1) == 1)
                    {
                        ifdDataOffset++;
                    }
                }
            }

            return(new IFDEntryInfo(ifdEntries, startOffset, ifdDataOffset));
        }