/// <summary> /// ReadRotation reads a scaling and resolution information for image marks. /// </summary> /// <remarks> /// This methods aplies when the specifications are mentionning the availability of a AN_NEW_ROTATE_STRUCT structure. /// </remarks> /// <param name="stream">The stream to read the data in.</param> /// <param name="dataSize">The size of the data to read.</param> /// <returns>The data read, null if an error occured.</returns> public static WangRotation ReadRotation(IWangStream stream, int dataSize) { // The expected data size is fixed. if (dataSize == 56) { /* * This implementation is based on the following C++ typedef: * typedef struct tagAnNewRotateStruct{ * int rotation; // 1=Original * // 2=Rotate right (90 degrees clockwise) * // 3=Flip (180 degrees clockwise) * // 4=Rotate left (270 degrees clockwise) * // 5=Vertical mirror (reflected around a * // vertical line) * // 6=Vertical mirror + Rotate right * // 7=Vertical mirror + Flip * // 8=Vertical mirror + Rotate left * int scale; // Set to 1000. * int nHRes; // Set to value of nOrigHRes. * int nVRes; // Set to value of nOrigVRes. * int nOrigHRes; // Resolution of image mark in DPI. * int nOrigVRes; // Resolution of image mark in DPI. * BOOL bReserved1; // Set to 0. * BOOL bReserved2; // Set to 0. * int nReserved[6]; * }AN_NEW_ROTATE_STRUCT; */ int rotation = stream.ReadInt32(); int scale = stream.ReadInt32(); #if DEBUG Debug.Assert(scale == 1000); #endif //DEBUG int nHRes = stream.ReadInt32(); int nVRes = stream.ReadInt32(); int horizontalResolution = stream.ReadInt32(); int verticalResolution = stream.ReadInt32(); #if DEBUG // This equality is part of the specifications but does not occur every time. // Debug.Assert(nHRes == readData.OrigHRes); // This equality is part of the specifications but does not occur every time. // Debug.Assert(nVRes == readData.OrigVRes); #endif //DEBUG stream.SkipBytes(4); stream.SkipBytes(4); stream.SkipBytes(6 * 4); return(new WangRotation(rotation, horizontalResolution, verticalResolution)); } return(null); }
/// <summary> /// ReadRgbQuad reads a structure designed to hold a color for a Wang annotation. /// </summary> /// <remarks> /// This methods aplies when the specifications are mentionning the availability of an RGBQUAD structure. /// </remarks> /// <param name="colors">An array to retrieve the components for the color.</param> /// <param name="stream">The stream to read the data in.</param> /// <returns>true if success otherwise false.</returns> public static bool ReadRgbQuad(byte[] colors, IWangStream stream) { if (stream.AvailableBytes() >= 4) { // The order is blue, green, red. stream.ReadBytes(colors, 3); // Skip the reserved data field. stream.SkipBytes(1); return(true); } return(false); }
/// <summary> /// ReadPoints reads a structure designed to hold points. /// </summary> /// <remarks> /// This methods aplies when the specifications are mentionning the availability of a AN_POINTS structure. /// </remarks> /// <param name="stream">The stream to read the data in.</param> /// <param name="dataSize">The size of the data to read.</param> /// <returns>The data read, null if an error occured.</returns> public static int[] ReadPoints(IWangStream stream, int dataSize) { /* * This implementation is based on the following C++ typedef: * typedef struct tagAnPoints{ * int nMaxPoints; // The maximum number of points; must * // be equal to the value of nPoints. * int nPoints; // The current number of points. * POINT ptPoint[1]; // Points marking the beginning and * // ending of the line segment(s); in * // FULLSIZE (not scaled) coordinates * // relative to the upper left corner * // of lrBounds in * // OIAN_MARK_ATTRIBUTES. * } AN_POINTS; */ // We need at least two integers. if (dataSize < 8) { return(null); } int max = stream.ReadInt32(); int count = stream.ReadInt32(); // Although the available spec explains the opposite, max and count may be different if (max < count) { return(null); } // The size of the data is exactly the size of two integers // plus the size for the maximum number of points. if ((8 + max * 2 * 4) != dataSize) { return(null); } int coordinatesCount = 2 * count; int[] readData = new int[coordinatesCount]; stream.ReadInts32(readData, coordinatesCount); // Although the available spec explains the opposite, max and count may be different // and we have to skip the unused data. // 2 coordinates, 4 bytes per coordinate stream.SkipBytes((max - count) * 2 * 4); return(readData); }
/// <summary> /// ReadDisplayText reads a structure designed to hold display text. /// </summary> /// <remarks> /// This methods aplies when the specifications are mentionning the availability of a OIAN_TEXTPRIVDATA structure. /// </remarks> /// <param name="stream">The stream to read the data in.</param> /// <param name="dataSize">The size of the data to read.</param> /// <returns>The data read.</returns> public static WangDisplayText ReadDisplayText(IWangStream stream, int dataSize) { // At least 4 values with 4 bytes are required if (dataSize >= 16) { /* * Type Name Description * int nCurrentOrientation Angle of text baseline to image in tenths of a degree; valid values are 0, 900, 1800, 2700. * * UINT uReserved1 Always 1000 when writing ignore when reading. * * UINT uCreationScale Always 72000 divided by the vertical resolution of the base image when writing. * Used to modify the Attributes.lfFont.lfHeight variable for display. * * UINT uAnoTextLength 64K byte limit (32K for multi-byte data) for Attach-a-Note, typed text, text from file; * 255 byte limit for text stamp. * * char szAnoText[*] Text string for text mark types. */ int orientation = stream.ReadInt32(); #if DEBUG Debug.Assert(orientation == 0 || orientation == 900 || orientation == 1800 || orientation == 2700); #endif // DEBUG UInt32 uReserved1 = stream.ReadUint32(); #if DEBUG // 1000 is the value described within the specs but we have some cases with something else. // Debug.Assert(uReserved1 == 1000 ); #endif // DEBUG uint creationScale = stream.ReadUint32(); int textSize = (int)stream.ReadUint32(); // It is necessary to have enough data for the characters. if (textSize <= (dataSize - 16)) { string text = WangAnnotationStructureReader.ReadCharString(stream, textSize); stream.SkipBytes(dataSize - 16 - textSize); return(new WangDisplayText(orientation, creationScale, text)); } } return(null); }
/// <summary> /// ReadHeader reads the header for the tag holding the Wang annotations. /// </summary> /// <param name="stream">The stream to read the data in.</param> /// <returns>true if the operation succeeded otherwise returns false.</returns> public static bool ReadHeader(IWangStream stream) { if (stream.AvailableBytes() >= 8) { /* * The annotation data itself consists of a 4-byte header, which is not currently used (reserved for future use). * The header should be skipped on read and written as zeros. Note, however, that it is included in the TIFF tag's Data Count field. * The header is followed by four bytes in Intel order that specify size of INTs and UINTs and byte ordering: * 4 bytes: * 0 = Intel 16-bit (least-significant byte to most-significant byte and two-byte INTs and UINTs) * 1 = Intel 32-bit (least-significant byte to most-significant byte and four-byte INTs and UINTs) */ stream.SkipBytes(4); if (stream.ReadInt32() == 0) { // 0 = Intel 16-bit (least-significant byte to most-significant byte and two-byte INTs and UINTs) // TODO - David Ometto - 2016-11-21 - Add support for 16-bit annotations. // TODO - David Ometto - 2016-11-21 - Find a good way to send the error. } return(true); } return(false); }
/// <summary> /// ReadMarkAttributes reads a structure designed to hold mark attributes. /// </summary> /// <remarks> /// This methods aplies when the specifications are mentionning the availability of a OIAN_MARK_ATTRIBUTES structure. /// </remarks> /// <param name="stream">The stream to read the data in.</param> /// <param name="dataSize">The size of the data to read.</param> /// <returns>The data read.</returns> public static WangMarkAttributes ReadMarkAttributes(IWangStream stream, int dataSize) { // The expected data size is fixed. if (dataSize == 164) { /* * Type Name Description * UINT uType The type of the mark. * LRECT lrBounds Rectangle in FULLSIZE units; equivalent to type RECT. * Can be a rectangle or two points. * RGBQUAD rgbColor1 The main color; for example, the color of all lines, all rectangles, and standalone text. * RGBQUAD rgbColor2 The secondary color; for example, the color of the text of an Attach-a-Note. * BOOL bHighlighting TRUE - The mark is drawn highlighted. Highlighting * performs the same function as a highlighting marker on a * piece of paper. Valid only for lines, rectangles, and * freehand. * BOOL bTransparent TRUE - The mark is drawn transparent. A transparent * mark does not draw white pixels. That is, transparent * replaces white pixels with whatever is behind those pixels. * Available only for images. * UINT uLineSize The width of the line in pixels. * UINT uReserved1 Reserved; must be set to 0. * UINT uReserved2 Reserved; must be set to 0. * LOGFONT lfFont The font information for the text, consisting of standard * font attributes of font size, name, style, effects, and * background color. * DWORD bReserved3 Reserved; must be set to 0. * time_t Time The time that the mark was first saved, in seconds, from * 00:00:00 1-1-1970 GMT. Every annotation mark has * time as one of its attributes. If you do not set the time before * the file is saved, the time is set to the date and time that the * save was initiated. This time is in the form returned by the * "time" C call, which is the number of seconds since * midnight 00:00:00 on 1-1-1970 GMT. If necessary, refer * to your C documentation for a more detailed description. * BOOL bVisible TRUE - The mark is currently set to be visible. * Annotation marks can be visible or hidden. * DWORD dwReserved4 Reserved; must be set to 0x0FF83F. * long lReserved[10] Must be set to 0. */ uint uintMarkType = stream.ReadUint32(); WangMarkType type = uintMarkType < ConversionWangMarkTypes.Length ? ConversionWangMarkTypes[uintMarkType] : WangMarkType.Invalid; WangMarkAttributes readData = new WangMarkAttributes(type); if (!WangAnnotationStructureReader.ReadRectangle(readData.Bounds, stream)) { return(null); } if (!WangAnnotationStructureReader.ReadRgbQuad(readData.Color1, stream)) { return(null); } if (!WangAnnotationStructureReader.ReadRgbQuad(readData.Color2, stream)) { return(null); } readData.Highlighting = WangAnnotationStructureReader.ReadBool(stream); readData.Transparent = WangAnnotationStructureReader.ReadBool(stream); readData.LineSize = stream.ReadUint32(); uint uReserved1 = stream.ReadUint32(); #if DEBUG // Reserved; must be set to 0. Debug.Assert(uReserved1 == 0); #endif // DEBUG uint uReserved2 = stream.ReadUint32(); #if DEBUG // Reserved; must be set to 0. Debug.Assert(uReserved2 == 0); #endif // DEBUG readData.LogFont = ReadLogfont(stream); uint bReserved3 = stream.ReadUint32(); #if DEBUG // Reserved; must be set to 0. // For some reason several file have a non 0 value there. // Debug.Assert(bReserved3 == 0); #endif // DEBUG // Skip time // TODO - David Ometto - 2016-11-21 - Add support for reading time_t structure. stream.SkipBytes(8); readData.Visible = WangAnnotationStructureReader.ReadBool(stream); // Reserved; must be set to 0x0FF83F... but for some reason several file have a non 0 value there. uint dwReserved4 = stream.ReadUint32(); // Skip 10 reserved long must be set to 0 (which is not true all of the time). stream.SkipBytes(40); return(readData); } else { return(null); } }
/// <summary> /// ReadBlock reads the block and updates the properties accordingly. /// </summary> /// <param name="properties">The properties to update.</param> /// <param name="stream">The stream to read the data in.</param> /// <param name="dataSize">The size of the block.</param> /// <returns>true if the operation succeeded otherwise returns false.</returns> public static bool ReadBlock(WangAnnotationProperties properties, IWangStream stream, int dataSize) { #if DEBUG Debug.Assert(stream.AvailableBytes() >= dataSize); #endif // DEBUG WangNamedBlockHeader header = WangAnnotationStructureReader.ReadNamedBlockHeader(stream, dataSize); if (header == null || header.Size > stream.AvailableBytes()) { return(false); } /* * Named Block Associated Structure Usage * OiAnoDat For lines: AN_POINTS List coordinates for lines and freehand marks. * For images:AN_NEW_ROTATE_STRUCT Hold scaling and resolution information for image marks. * OiFilNam AN_NAME_STRUCT Hold file name for image marks. * OiDIB AN_IMAGE_STRUCT Store DIB data. * OiGroup (required) STR Create sets of marks (required). * OiIndex (required) STR Assign unique number, originating at 0, for each mark. * To facilitate easy application control, the next available number is generated by incrementing by 1 the number just assigned and storing it in the default OiIndex mark. * OiAnText OIAN_TEXTPRIVDATA Display text annotation marks. * OiHypLnk HYPERLINK_NB Turn mark into a hyperlink. */ if (header.Name == "OiAnoDat") { // TODO - David Ometto - 2016-11-24 - Unit test this method return(ReadAnoDatBlock(properties, stream, header.Size)); } else if (header.Name == "OiFilNam") { properties.SetFilename(WangAnnotationStructureReader.ReadCharString(stream, header.Size)); return(true); } else if (header.Name == "OiDIB") { properties.SetDibInfo(WangAnnotationStructureReader.ReadDib(stream, header.Size)); return(true); } else if (header.Name == "OiGroup") { properties.OiGroup = WangAnnotationStructureReader.ReadCharString(stream, header.Size); return(true); } else if (header.Name == "OiIndex") { properties.OiIndex = WangAnnotationStructureReader.ReadCharString(stream, header.Size); return(true); } else if (header.Name == "OiAnText") { WangDisplayText displayText = WangAnnotationStructureReader.ReadDisplayText(stream, header.Size); if (displayText == null) { return(false); } properties.SetDisplayText(displayText); return(true); } else if (header.Name == "OiHypLnk") { WangHyperlink hyperlink = WangAnnotationStructureReader.ReadHyperlink(stream, header.Size); if (hyperlink == null) { return(false); } properties.SetHyperlink(hyperlink); return(true); } else { // We just skip unknown data stream.SkipBytes(header.Size); return(true); } }