public ResolutionInfo(ImageResourceID id, string name, uint size, Reader reader) : base(id, name) { HorizontalResolution = reader.ReadInt16(); HorizontalResolutionUnit = (ResolutionUnit)reader.ReadInt32(); WidthUnit = (Unit)reader.ReadInt16(); VerticalResolution = reader.ReadInt16(); VerticalResolutionUnit = (ResolutionUnit)reader.ReadInt32(); HeightUnit = (Unit)reader.ReadInt16(); }
public AlphaChannelNames(ImageResourceID id, string name, uint size, Reader reader) : base(id, name) { names = new List <string>(); readonlyNames = new ReadOnlyCollection <string>(names); long endPosition = reader.BaseStream.Position + (long)size; while (reader.BaseStream.Position < endPosition) { string channelName = reader.ReadPSDString(); if (channelName.Length > 0) { names.Add(channelName); } } }
private static ImageResource CreateImageResource(ImageResourceID id, string name, uint size, Reader reader) { #region 만약 ImageResourceDictionary가 구축되어있지 않다면 구축합니다. if (imageResourceDictionary == null) { // ImageResource를 상속 받고, // ImageResourceAttribute를 정의하고, // (ImageResourceID, string, BinaryReader)를 입력받는 생성자를 정의한 class를 모읍니다. imageResourceDictionary = new Dictionary <ImageResourceID, Type>(); Assembly assembly = Assembly.GetCallingAssembly(); Type[] constructorParameterTypes = new Type[] { typeof(ImageResourceID), typeof(string), typeof(uint), typeof(Reader) }; foreach (Type item in assembly.GetExportedTypes()) { if (item.IsVisible && item.IsClass && item.IsAbstract == false && item.IsSubclassOf(typeof(ImageResource)) && item.GetConstructor(constructorParameterTypes) != null) { ImageResourceAttribute attribute = item.GetCustomAttribute <ImageResourceAttribute>(); if (attribute != null) { imageResourceDictionary.Add(attribute.ID, item); } } } } #endregion Type imageResourceType = null; if (imageResourceDictionary.TryGetValue(id, out imageResourceType)) { return((ImageResource)Activator.CreateInstance(imageResourceType, new object[] { id, name, size, reader })); } else { return(null); } }
private void Load(Stream stream, bool ignoreImageResources, bool ignoreLayers, bool ignoreLayerBitmaps, bool ignoreMergedBitmap) { Reader reader = new Reader(stream); #region PSD인지 검사합니다. { string signature = new string(reader.ReadChars(4)); if (signature != "8BPS") { throw new Exception("올바른 PSD File이 아닙니다."); } short version = reader.ReadInt16(); if (version != 1) { throw new Exception("PSD File의 Version이 맞지 않습니다."); } } #endregion int channels = 0; int width = 0; int height = 0; int bitsPerPixel = 0; ColorModes colorMode = ColorModes.RGB; #region Header를 읽어옵니다. { reader.BaseStream.Position += 6; // 예약분 channels = reader.ReadInt16(); height = reader.ReadInt32(); width = reader.ReadInt32(); bitsPerPixel = reader.ReadInt16(); colorMode = (ColorModes)reader.ReadInt16(); if (colorMode != ColorModes.RGB) { throw new Exception(string.Format("{0} Color Format인 PSD는 읽어올 수 없습니다. (가능한 Color Format : RGB)", colorMode)); } if (bitsPerPixel != 8) { throw new Exception(string.Format("한 Pixel이 Channel당 {0} byte인 PSD는 읽어올 수 없습니다. (가능한 Bytes : 1 Byte", bitsPerPixel / 8)); } } #endregion byte[] colorModeData = null; #region ColorModeData를 가져옵니다. { uint sectionSize = reader.ReadUInt32(); if (sectionSize > 0) { colorModeData = reader.ReadBytes((int)sectionSize); } } #endregion List <ImageResource> imageResources = new List <ImageResource>(); #region ImageResource들을 읽어옵니다. { uint sectionSize = reader.ReadUInt32(); if (sectionSize > 0) { long sectionEndPosition = reader.BaseStream.Position + (long)sectionSize; if (ignoreImageResources == false) { while (reader.BaseStream.Position < sectionEndPosition) { string signature = new string(reader.ReadChars(4)); if (signature != "8BIM" && signature != "MeSa") { throw new Exception("올바르지 않은 ImageResource가 존재합니다."); } ImageResourceID id = (ImageResourceID)reader.ReadInt16(); string name = reader.ReadPascalString(); uint size = reader.ReadUInt32(); long endPosition = reader.BaseStream.Position + (long)size; if (size > 0) { ImageResource resource = CreateImageResource(id, name, size, reader); if (resource != null) { imageResources.Add(resource); } } // 위치는 짝수로 맞춥니다. reader.BaseStream.Position = (endPosition % 2 == 0) ? endPosition : endPosition + 1; } } reader.BaseStream.Position = sectionEndPosition; } } #endregion List <Layer> layers = new List <Layer>(); #region Layer와 Mask 정보를 읽어옵니다. { uint sectionSize = reader.ReadUInt32(); if (sectionSize > 0) { long sectionEndPosition = reader.BaseStream.Position + (long)sectionSize; if (ignoreLayers == false) { #region Layer를 읽어옵니다. uint layersSize = reader.ReadUInt32(); if (layersSize > 0) { long layersEndPosition = reader.BaseStream.Position + (long)layersSize; //bool absoluteAlpha = false; short numberOfLayers = reader.ReadInt16(); if (numberOfLayers < 0) { //absoluteAlpha = true; numberOfLayers = Math.Abs(numberOfLayers); } #region Layer들의 기본 정보를 읽어서 보관합니다. for (short i = 0; i < numberOfLayers; i++) { layers.Add(new Layer(reader)); } #endregion #region Layer들의 Pixel 정보를 읽어옵니다. foreach (Layer layer in layers) { if (ignoreLayerBitmaps == false) { layer.ReadPixelData(bitsPerPixel, reader); } else { layer.SkipPixelData(bitsPerPixel, reader); } } #endregion #region Group을 정리합니다. { Stack <Layer> layerStack = new Stack <Layer>(layers.Count / 2); for (int i = layers.Count - 1; i >= 0; i--) { Layer item = layers[i]; bool isEndLayerSetTag = (item.Name.StartsWith("</Layer set>")) || (item.Name.StartsWith("</Layer group>")); if (layerStack.Count > 0 && isEndLayerSetTag == false) { layerStack.Peek().AddSubLayer(item); } if (item.IsGroup) { if (isEndLayerSetTag == false) { layerStack.Push(item); } else { layerStack.Pop(); layers.RemoveAt(i); } } } for (int i = 0; i < layers.Count;) { if (layers[i].Group != null) { layers.RemoveAt(i); } else { i++; } } } #endregion reader.BaseStream.Position = layersEndPosition; } #endregion #region Layer Global Mask 정보를 읽어옵니다. uint layerGlobalMaskSize = reader.ReadUInt32(); if (layerGlobalMaskSize > 0) { long layerGlobalMaskEndPosition = reader.BaseStream.Position + (long)layerGlobalMaskSize; reader.BaseStream.Position = layerGlobalMaskEndPosition; } #endregion #region Layer 추가 정보를 읽어옵니다. /* * while (reader.BaseStream.Position < sectionEndPosition) * { * string signature = new string(reader.ReadChars(4)); * string fourcc = new string(reader.ReadChars(4)); * uint additionalInfoLength = reader.ReadUInt32(); * long additionalInfoEndPosition = reader.BaseStream.Position + (long)additionalInfoLength; * * reader.BaseStream.Position = additionalInfoEndPosition; * } */ #endregion } reader.BaseStream.Position = sectionEndPosition; } #region Canvas 밖으로 나간 레이어 정보를 잘라냅니다. // Canvas 밖에 있는 레이어 픽셀 정보는 // 포토샵을 통해서 확인하기도 힘들고 잘라내기조차도 번거롭기 때문에 // 모두 잘라냅니다. foreach (var item in layers) { item.ClipByCanvas(width, height, true); } #endregion } #endregion Bitmap mergedImageData = null; byte[][] mergedImageChannelData = null; #region PSD 마지막 부분에 있는 합쳐진 Image를 읽어옵니다. int numberOfPixels = width * height; Compression compressionMode = (Compression)reader.ReadInt16(); mergedImageChannelData = new byte[channels][]; if (ignoreMergedBitmap == false) { #region Channel 별로 기록된 Pixel Data를 읽어옵니다. switch (compressionMode) { case Compression.RawData: for (int i = 0; i < mergedImageChannelData.Length; i++) { mergedImageChannelData[i] = reader.ReadRawPixelData(width, height, bitsPerPixel); } break; case Compression.RLECompression: // 행별로 열의 길이가 기록되어 있습니다만 무시합니다. reader.BaseStream.Position += height * channels * 2; for (int i = 0; i < mergedImageChannelData.Length; i++) { mergedImageChannelData[i] = reader.ReadRLECompressedPixelData(width, height, bitsPerPixel); } break; default: throw new Exception(string.Format("{0} 로 저장된 PSD는 읽어올 수 없습니다. (프로그래머에게 연락하세요)", compressionMode)); } #endregion #region BitmapContent에 Pixel들을 채워 넣습니다. switch (colorMode) { case ColorModes.RGB: if (channels == 3) { mergedImageData = MergeChannels(width, height, mergedImageChannelData[0], mergedImageChannelData[1], mergedImageChannelData[2], null); } else if (channels >= 4) { mergedImageData = MergeChannels(width, height, mergedImageChannelData[0], mergedImageChannelData[1], mergedImageChannelData[2], mergedImageChannelData[3]); } break; } #endregion } #endregion #region 읽어온 정보들을 Field에 설정합니다. this.Channels = channels; this.Width = width; this.Height = height; this.BitsPerPixel = bitsPerPixel; this.ColorMode = colorMode; this.imageResources = imageResources; this.layers = layers; this.readOnlyImageResources = new ReadOnlyCollection <ImageResource>(this.imageResources); this.readOnlyLayers = new ReadOnlyCollection <Layer>(this.layers); this.MergedBitmap = mergedImageData; #endregion }
public ImageResource(ImageResourceID id, string name) { ID = id; Name = name; }
public ImageResourceAttribute(ImageResourceID id) { ID = id; }