/// <summary> /// Extracts thumbnails from metadata and saves them to thumb directory /// </summary> /// <param name="directory">The directory which will be scanned</param> public static void ExtractThumbnails(string[] files) { SetProcess ("-q -q -previewImage -b -@ -", ExifArgument.Thumbnails); exiftool.Start (); byte[] data = Encoding.UTF8.GetBytes (String.Join ("\r\n", files)); exiftool.StandardInput.BaseStream.Write (data, 0, data.Length); exiftool.StandardInput.BaseStream.Close (); using(MemoryStream str = new MemoryStream()) { exiftool.StandardOutput.BaseStream.CopyTo (str); str.Position = 0; List<long> idx = new List<long>(); byte[] tmp = new byte[2]; for (long ct = 0; ct < str.Length; ct++) { str.Position = ct; str.Read (tmp, 0, 2); if (BitConverter.IsLittleEndian) Array.Reverse (tmp); if (BitConverter.ToUInt16 (tmp, 0) == JpgMarker) idx.Add (ct); } if (idx.Count != ProjectManager.CurrentProject.Frames.Count) throw new Exception("Not all images have a thumbnail"); BitmapEx tmpBmp = null; byte[] buffer; long length; for (int i = 0; i < idx.Count; i++) { if (ProjectManager.CurrentProject.MainWorker.CancellationPending) break; if (i + 1 < idx.Count) length = idx[i + 1] - idx[i]; else length = str.Length - idx[i]; buffer = new byte[length]; str.Position = idx[i]; str.Read (buffer, 0, (int)length); using(MemoryStream str2 = new MemoryStream(buffer)) { tmpBmp = new BitmapEx(str2).ScaleW (300); ProjectManager.CurrentProject.AddThumb (tmpBmp); //Normal Thumb ProjectManager.CurrentProject.AddThumb (tmpBmp); //Edit Thumb ProjectManager.CurrentProject.ReportWorkProgress (i, ProgressType.LoadThumbnails); } } if (tmpBmp != null) tmpBmp.Dispose (); buffer = null; } exiftool.WaitForExit(); exiftool.Dispose(); }
/// <summary> /// Adds a thumb to the list /// </summary> /// <param name="thumb">The thumb to be added</param> public void AddThumb(BitmapEx thumb) { if (MainStream.CanWrite) { if (thumb.IsPinned) { thumb.UnlockBits(); } MainStream.Position = MainStream.Length; long begin = MainStream.Length; formatter.Serialize(MainStream, thumb); Entries.Add(new DataEntry(begin, MainStream.Length)); } }
/// <summary> /// Resizes this image to a new size with bi-cubic interpolation /// </summary> /// <param name="nWidth">New Width</param> /// <param name="nHeight">New Height</param> /// <returns>The resized image</returns> public BitmapEx Scale(uint nWidth, uint nHeight) { if (nWidth == Width && nHeight == Height) { return(this.Clone()); } BitmapEx bmpN = new BitmapEx(nWidth, nHeight, this.BitDepth); try { this.LockBits(); bmpN.LockBits(); switch (this.BitDepth) { case ImageType.RGB8: case ImageType.RGBA8: DoScale8(bmpN, nWidth, nHeight); break; case ImageType.RGB16: case ImageType.RGBA16: DoScale16(bmpN, nWidth, nHeight); break; case ImageType.RGB32: case ImageType.RGBA32: DoScale32(bmpN, nWidth, nHeight); break; case ImageType.RGB64: case ImageType.RGBA64: DoScale64(bmpN, nWidth, nHeight); break; default: throw new ArgumentException("Bitdepth not supported"); } } finally { this.UnlockBits(); bmpN.UnlockBits(); } return(bmpN); }
public static Pixbuf ConvertToPixbuf(BitmapEx bmpEx) { int bitspersample; bool HasAlpha; if (bmpEx.BitDepth == ImageType.RGB8) { bitspersample = 8; HasAlpha = false; } else if (bmpEx.BitDepth == ImageType.RGBA8) { bitspersample = 8; HasAlpha = true; } else if (bmpEx.BitDepth == ImageType.RGB16) { bitspersample = 16; HasAlpha = false; } else if (bmpEx.BitDepth == ImageType.RGBA16) { bitspersample = 16; HasAlpha = true; } else throw new ArgumentException("Bitdepth not supported"); byte[] data = new byte[bmpEx.Height * bmpEx.Stride]; bmpEx.LockBits(); unsafe { System.Runtime.InteropServices.Marshal.Copy(bmpEx.Scan0, data, 0, data.Length); } bmpEx.UnlockBits(); return new Pixbuf(data, HasAlpha, bitspersample, (int)bmpEx.Width, (int)bmpEx.Height, (int)bmpEx.Stride); }
public static Bitmap ConvertToBitmap(BitmapEx bmpEx) { uint depth = 0; bool HasAlpha; PixelFormat format; if (bmpEx.BitDepth == ImageType.RGB8) { format = PixelFormat.Format24bppRgb; depth = 3; HasAlpha = false; } else if (bmpEx.BitDepth == ImageType.RGBA8) { format = PixelFormat.Format32bppArgb; depth = 4; HasAlpha = true; } else if (bmpEx.BitDepth == ImageType.RGB16) { format = PixelFormat.Format48bppRgb; depth = 6; HasAlpha = false; } else if (bmpEx.BitDepth == ImageType.RGBA16) { format = PixelFormat.Format64bppArgb; depth = 8; HasAlpha = true; } else throw new ArgumentException("Bitdepth not supported"); Bitmap outBmp = new Bitmap((int)bmpEx.Width, (int)bmpEx.Height, format); BitmapData bmd = outBmp.LockBits(new System.Drawing.Rectangle(0, 0, outBmp.Width, outBmp.Height), ImageLockMode.WriteOnly, outBmp.PixelFormat); bmpEx.LockBits(); unsafe { byte* pixIn = (byte*)bmpEx.Scan0; byte* pixOut = (byte*)bmd.Scan0; long idx; uint x, y; int resV = (int)(bmd.Stride - bmpEx.Stride); int res = 0; for (y = 0; y < bmd.Height; y++) { for (x = 0; x < bmd.Stride; x+=depth) { idx = y * bmd.Stride + x; pixOut[idx + 2] = pixIn[idx - res]; pixOut[idx + 1] = pixIn[idx + 1 - res]; pixOut[idx] = pixIn[idx + 2 - res]; if (HasAlpha) pixOut[idx + 3] = pixIn[idx + 3 - res]; } res += resV; } } outBmp.UnlockBits(bmd); bmpEx.UnlockBits(); return outBmp; }
protected override void LoadThumbnails(string[] files) { BitmapEx bmpTmp = null; for (int i = 0; i < Frames.Count; i++) { if (MainWorker.CancellationPending) { return; } bmpTmp = new BitmapEx(Frames[i].FilePath); SetThumb(i, bmpTmp); Frames[i].Width = (int)bmpTmp.Width; Frames[i].Height = (int)bmpTmp.Height; ReportWorkProgress(i * 100 / Frames.Count, ProgressType.LoadThumbnails); } if (bmpTmp != null) { bmpTmp.Dispose(); } }
private void BrCalc_Simple() { if (SimpleCalculationArea.Height < 0 || SimpleCalculationArea.Width < 0 || SimpleCalculationArea.X < 0 || SimpleCalculationArea.Y < 0 || SimpleCalculationArea.Height > Frames[0].Height || SimpleCalculationArea.Width > Frames[0].Width) { throw new ArgumentException("Calculation area must be on thumb image"); } for (int f = 0; f < Frames.Count; f++) { double Brightness = 0; long index = 0; int pixcount = 0; BitmapEx bmp = GetThumb(f, false).Scale(300, 200); unsafe { bmp.LockBits(); byte *pix = (byte *)bmp.Scan0; for (int y = SimpleCalculationArea.X; y < SimpleCalculationArea.Height; y++) { for (int x = SimpleCalculationArea.Y; x < SimpleCalculationArea.Width; x++) { index = y * bmp.Stride + x * bmp.ChannelCount; Brightness += Math.Sqrt(Math.Pow(pix[index], 2) * 0.241 + Math.Pow(pix[index + 1], 2) * 0.691 + Math.Pow(pix[index + 2], 2) * 0.068); pixcount++; } } bmp.UnlockBits(); } Frames[f].OriginalBrightness = Brightness / pixcount; Frames[f].AlternativeBrightness = Frames[f].OriginalBrightness; Frames[f].NewBrightness = Frames[f].OriginalBrightness; } }
/// <summary> /// Gets a thumb from the list /// </summary> /// <param name="index">Index of the thumb</param> /// <param name="UseBuffer">If true, it will add the file to the buffer</param> /// <returns>The thumb or null if not found</returns> public BitmapEx this[int index, bool UseBuffer = true] { get { if (index < 0 || index >= Entries.Count || !MainStream.CanRead) { return(null); } tmpBuff = Buffer.FirstOrDefault(t => t.Index == index); if (tmpBuff != null) { return(tmpBuff.Value); } MainStream.Position = Entries[index].Begin; if (UseBuffer) { tmpBmp = (BitmapEx)formatter.Deserialize(MainStream); Buffer.Enqueue(new BufferEntry(index, tmpBmp)); return(tmpBmp); } else { return((BitmapEx)formatter.Deserialize(MainStream)); } } set { if (index >= 0 && index < Entries.Count && MainStream.CanWrite) { MainStream.Position = Entries[index].Begin; formatter.Serialize(MainStream, value); } } }
public void SetThumbEdited(int index, BitmapEx thumb) { ThumbsStorage[index * 2 + 1] = thumb; }
public static NSImage ToNSImage(BitmapEx bmpEx) { bmpEx.LockBits(); long bufferLength = bmpEx.Width * bmpEx.Height; CGDataProvider provider = new CGDataProvider(bmpEx.Scan0, (int)bufferLength); int bitsPerComponent, bitsPerPixel, bytesPerRow = (int)bmpEx.Stride; CGColorSpace colorSpaceRef = CGColorSpace.CreateDeviceRGB(); switch (bmpEx.BitDepth) { case ImageType.RGB16: bitsPerComponent = 16; bitsPerPixel = 48; bufferLength *= 3; break; case ImageType.RGBA16: bitsPerComponent = 16; bitsPerPixel = 64; bufferLength *= 4; break; case ImageType.RGB8: bitsPerComponent = 8; bitsPerPixel = 24; bufferLength *= 3; break; case ImageType.RGBA8: bitsPerComponent = 8; bitsPerPixel = 32; bufferLength *= 4; break; case ImageType.RGB32: bitsPerComponent = 32; bitsPerPixel = 96; bufferLength *= 3; break; case ImageType.RGBA32: bitsPerComponent = 32; bitsPerPixel = 128; bufferLength *= 4; break; case ImageType.RGB64: bitsPerComponent = 64; bitsPerPixel = 192; bufferLength *= 3; break; case ImageType.RGBA64: bitsPerComponent = 64; bitsPerPixel = 256; bufferLength *= 4; break; default: throw new ArgumentException("Bitdepth not supported"); } CGImage img = new CGImage((int)bmpEx.Width, (int)bmpEx.Height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, CGBitmapFlags.ByteOrderDefault, provider, null, true, CGColorRenderingIntent.Default); bmpEx.UnlockBits(); return new NSImage(img, new SizeF(img.Width, img.Height)); }
/// <summary> /// Adds a thumb to the thumb storage /// </summary> /// <param name="thumb">The thumbnail</param> internal void AddThumb(BitmapEx thumb) { ThumbsStorage.AddThumb(thumb); }
private unsafe void DoScale64(BitmapEx bmpN, uint nWidth, uint nHeight) { long dstOffset = bmpN.Stride - 3 * nWidth; decimal xFactor = Width / (decimal)nWidth; decimal yFactor = Height / (decimal)nHeight; ulong *src = (ulong *)this.Scan0; ulong *dst = (ulong *)bmpN.Scan0; ulong *p; decimal ox, oy, dx, dy, k1, k2, r, g, b; uint ox1, oy1, ox2, oy2, y, x; uint ymax = Height - 1; uint xmax = Width - 1; int n, m; byte cc = this.ChannelCount; for (y = 0; y < nHeight; y++) { oy = y * yFactor - 0.5m; oy1 = (uint)oy; dy = oy - oy1; for (x = 0; x < nWidth; x++, dst += cc) { ox = x * xFactor - 0.5m; ox1 = (uint)ox; dx = ox - ox1; r = g = b = 0; for (n = -1; n < 3; n++) { k1 = BiCubicKernelDecimal(dy - n); oy2 = (uint)(oy1 + n); if (oy2 < 0) { oy2 = 0; } if (oy2 > ymax) { oy2 = ymax; } for (m = -1; m < 3; m++) { k2 = k1 * BiCubicKernelDecimal(m - dx); ox2 = (uint)(ox1 + m); if (ox2 < 0) { ox2 = 0; } if (ox2 > xmax) { ox2 = xmax; } p = src + oy2 * Stride + ox2 * cc; r += k2 * p[0]; g += k2 * p[1]; b += k2 * p[2]; } } dst[0] = (ulong)Math.Max(0, Math.Min(18446744073709551615, r)); dst[1] = (ulong)Math.Max(0, Math.Min(18446744073709551615, g)); dst[2] = (ulong)Math.Max(0, Math.Min(18446744073709551615, b)); } dst += dstOffset; } }
public BufferEntry(int Index, BitmapEx Value) { this.Index = Index; this.Value = Value; }
protected override void LoadThumbnails(string[] files) { BitmapEx bmpTmp = null; for (int i = 0; i < Frames.Count; i++) { if (MainWorker.CancellationPending) { return; } bmpTmp = new BitmapEx(Frames[i].FilePath); SetThumb(i, bmpTmp); Frames[i].Width = (int)bmpTmp.Width; Frames[i].Height = (int)bmpTmp.Height; ReportWorkProgress(i * 100 / Frames.Count, ProgressType.LoadThumbnails); } if (bmpTmp != null) bmpTmp.Dispose(); }
public void SetThumb(int index, BitmapEx thumb) { ThumbsStorage[index * 2] = thumb; }
private unsafe void DoScale8(BitmapEx bmpN, uint nWidth, uint nHeight) { long dstOffset = 0; double xFactor = Width / (double)nWidth; double yFactor = Height / (double)nHeight; byte* src = (byte*)this.Scan0; byte* dst = (byte*)bmpN.Scan0; byte* p; double ox, oy, dx, dy, k1, k2, r, g, b; uint ox1, oy1, ox2, oy2, y, x; uint ymax = Height - 1; uint xmax = Width - 1; int n, m; byte cc = this.ChannelCount; for (y = 0; y < nHeight; y++) { oy = y * yFactor - 0.5d; oy1 = (uint)oy; dy = oy - oy1; for (x = 0; x < nWidth; x++, dst += cc) { ox = x * xFactor - 0.5d; ox1 = (uint)ox; dx = ox - ox1; r = g = b = 0; for (n = -1; n < 3; n++) { k1 = BiCubicKernel(dy - n); oy2 = (uint)(oy1 + n); if (oy2 < 0) oy2 = 0; if (oy2 > ymax) oy2 = ymax; for (m = -1; m < 3; m++) { k2 = k1 * BiCubicKernel(m - dx); ox2 = (uint)(ox1 + m); if (ox2 < 0) ox2 = 0; if (ox2 > xmax) ox2 = xmax; p = src + oy2 * Stride + ox2 * cc; r += k2 * p[0]; g += k2 * p[1]; b += k2 * p[2]; } } dst[0] = (byte)Math.Max(0, Math.Min(255, r)); dst[1] = (byte)Math.Max(0, Math.Min(255, g)); dst[2] = (byte)Math.Max(0, Math.Min(255, b)); } dst += dstOffset; } }
/// <summary> /// Resizes this image to a new size with bi-cubic interpolation /// </summary> /// <param name="nWidth">New Width</param> /// <param name="nHeight">New Height</param> /// <returns>The resized image</returns> public BitmapEx Scale(uint nWidth, uint nHeight) { if (nWidth == Width && nHeight == Height) return this.Clone(); BitmapEx bmpN = new BitmapEx(nWidth, nHeight, this.BitDepth); try { this.LockBits(); bmpN.LockBits(); switch (this.BitDepth) { case ImageType.RGB8: case ImageType.RGBA8: DoScale8(bmpN, nWidth, nHeight); break; case ImageType.RGB16: case ImageType.RGBA16: DoScale16(bmpN, nWidth, nHeight); break; case ImageType.RGB32: case ImageType.RGBA32: DoScale32(bmpN, nWidth, nHeight); break; case ImageType.RGB64: case ImageType.RGBA64: DoScale64(bmpN, nWidth, nHeight); break; default: throw new ArgumentException("Bitdepth not supported"); } } finally { this.UnlockBits(); bmpN.UnlockBits(); } return bmpN; }