Bitmap in einen Byte Array konvertieren

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 26 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

    hehehe ... es muss natürlich 300 KB heißen ... gut aufgepasst ! :)

    VaporiZed schrieb:

    Ich hab irgendwo den Faden verloren. Wo sind wir denn nun codiertechnisch bei PNG?


    Ich bin sehr dankbar für eure Hilfe und Ideen .... aber jetzt mal ganz offen: was soll denn soviel besser sein an einer Konvertierung etwa in einen .png file (die ich auch nicht lückenlos verstehe) als an meiner Umgehung ? Ich drehe das Dingens um 360 Grad und die Sache funzt !

    Aber natürlich war mir das Gespräch mit euch wichtig. Denn so eine Umgehung mache ich natürlich nur, wenn ich mir absolut sicher bin, dass ich nicht irgend einen blöden Fehler gemacht habe! Was bei mir ja immer mal der Fall sein kann ... :)

    Vielen Dank für eure unendliche Mühe ... ihr habt mir SEHR geholfen !

    LG
    Peter

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Peter329“ ()

    Peter329 schrieb:

    aber jetzt mal ganz offen: was soll denn soviel besser sein an einer Konvertierung etwa in einen .png file (die ich auch nicht lückenlos verstehe) als an meiner Umgehung ? Ich drehe das Dingens um 360 Grad und die Sache funzt !
    Klar, kannst Du machen. Dadurch verschleierst Du aber m.E. den Fehler. Es bleibt bei Dir somit im Ungewissen, warum Du erst das Ding um 360° drehen musst, damit es klappt. Und wenn Du dann in nem Jahr Dir den Code anschaust, denkst Du Dir vielleicht: "Was'n das für'n Mist? Die Zeile ist ja total sinnlos! Weg damit!" -> Fehler. Und Du denkst Dir: "WTF!?!" Mir ist klar, dass wir immer noch nicht endgültig herausgefunden haben, wo der Fehler liegt, aber eine Funktion anzuwenden, die einen Effekt hat, für den sie nicht gedacht/gemacht wurde, sehe ich als kritisch an.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Na ja, die Sache muss man in JEDEM Fall kommentieren. Egal ob man dreht oder konvertiert ! Und das mache ich auch ... weil ich sehr vergesslich bin, hehehe ...

    Aber eine Umgehung bleibt eine Umgehung.

    Mir wäre das auch lieber, wir würden die Ursache für den GDI+ Fehler finden und könnten das Programm "nach der reinen Lehre" zum Laufen kriegen.

    Aber andererseits macht es auch keinen Sinn in Schönheit zu sterben. Und weil es derzeit keine "saubere" Lösung gibt, habe ich mich nun entschlossen, dass Dingens zu "drehen" ... auch wenn es mir nicht so richtig gefällt.

    LG
    Peter
    Ich werd das Gefühl nicht los, dass die Original-Bitmap irgendwie gesperrt ist und daher der GDI+-Fehler auftritt, wenn man versucht, die irgendwohin zu verschieben/kopieren und durch das Rotieren heimlich eine neue Bitmap entsteht oder zumindest die alte freigegeben wird. Ich konnte allerdings nix in der Doku diesbezüglich bisher finden.
    Durch Erstellung einer einfachen Bitmap-Kopie geht das Abspeichern nämlich auch. Auch bei JPEG:

    VB.NET-Quellcode

    1. Private Sub SaveFile()
    2. Using TemporaryBitmap = New Bitmap(bitmap1)
    3. Using ms As New MemoryStream()
    4. Dim myImageCodecInfo As ImageCodecInfo = GetEncoderInfo(ImageFormat.Jpeg)
    5. Dim myEncoder As Encoder = Encoder.Quality
    6. Dim QualityLevel As Integer = 95
    7. Dim myEncoderParameters As New EncoderParameters(1)
    8. Dim myEncoderParameter As New EncoderParameter(myEncoder, QualityLevel)
    9. myEncoderParameters.Param(0) = myEncoderParameter
    10. TemporaryBitmap.Save(ms, myImageCodecInfo, myEncoderParameters)
    11. bytes = ms.ToArray()
    12. End Using
    13. End Using
    14. 'Save byte array to file
    15. IO.File.WriteAllBytes(myObject, bytes)
    16. MessageBox.Show("OK,file was saved.")
    17. End Sub

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Peter329 schrieb:

    die Ursache für den GDI+ Fehler
    Ich hab mal nach dem Fehlercode gegoogelt: HResult = &H80004005, das ist sehr tief im System.

    ====
    Ich würde mal auf die WPF-Funktionalität umsteigen mit den Verweisen { PresentationCore, PresentationFramework, WindowsBase } und { Imports System.Windows.Media.Imaging }.
    In C# sieht das so aus:
    Spoiler anzeigen

    C#-Quellcode

    1. // Creates an image with the pre-defined pattern
    2. BitmapSource image = BitmapSource.Create(
    3. _Width, _Height,
    4. 96, 96,
    5. PixelFormats.Gray16,
    6. null, // BitmapPalettes.Gray16,
    7. _Pixels,
    8. _Stride);

    C#-Quellcode

    1. private void performStandardJpeg(BitmapSource image, string file, int level)
    2. {
    3. using (FileStream stream = new FileStream(file, FileMode.Create))
    4. {
    5. JpegBitmapEncoder encoder = new JpegBitmapEncoder();
    6. encoder.QualityLevel = level; // standard: 75
    7. encoder.Frames.Add(BitmapFrame.Create(image));
    8. encoder.Save(stream);
    9. }
    10. }
    Da musst Du Dich mal durchfräsen, ich hab da mal ein Projekt gemacht, wo verschiedene Formate gespeichert wurden:
    Spoiler anzeigen

    Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Windows;
    6. using System.Windows.Controls;
    7. using System.Windows.Data;
    8. using System.Windows.Documents;
    9. using System.Windows.Input;
    10. using System.Windows.Media;
    11. using System.Windows.Media.Imaging;
    12. using System.Windows.Navigation;
    13. using System.Windows.Shapes;
    14. using System.IO;
    15. using System.Diagnostics;
    16. using System.Windows.Threading;
    17. using System.Collections.ObjectModel;
    18. using System.Security.Permissions;
    19. namespace WpfApplication1
    20. {
    21. /// <summary>
    22. /// Interaction logic for MainWindow.xaml
    23. /// </summary>
    24. public partial class MainWindow : Window
    25. {
    26. /// <summary>pattern array to generate images, and compare it</summary>
    27. private ushort[] _Pixels;
    28. /// <summary>x dimensions of the calculated image</summary>
    29. private const int _Width = 512;//2048;//512 * 2;// * 10;
    30. /// <summary>y dimensions of the calculated image</summary>
    31. private const int _Height = 512;//128;//256 * 2;// * 10;
    32. /// <summary>sride of the calculated image - length of a single line in byte</summary>
    33. private const int _Stride = _Width * 2;
    34. // to generate noise
    35. private int _RandomRange = 256;
    36. private Random _Random;
    37. // Format string for full file path name
    38. private const string _FmtWdp1 = "{0}__{1}lossless.wdp";
    39. private const string _FmtWdp2 = "{0}__{1}lossy.wdp";
    40. private const string _FmtTiff = "{0}__{1}bitmap.tiff";
    41. private const string _FmtJpeg = "{0}__{1}jpeg.jpeg";
    42. // image and log paths
    43. private string _ImagePath1 = @"C:\Temp\BitmapEncoder\";
    44. private string _ImagePath2 = @"C:\Temp\png\ReconstructionPrecise\";
    45. private string _LogFile1;
    46. private string _LogFile2;
    47. private string _LogFile3;
    48. private enum ImageFormats
    49. {
    50. wdp,
    51. tiff,
    52. }
    53. private class MethodMark
    54. {
    55. private string file;
    56. private long milliSeconds;
    57. private long fileSize;
    58. public MethodMark(string f, long ms, long fs)
    59. {
    60. file = f;
    61. milliSeconds = ms;
    62. fileSize = fs;
    63. }
    64. public MethodMark(string f, Stopwatch stw)
    65. {
    66. milliSeconds = stw.ElapsedMilliseconds;
    67. FileInfo fi = new FileInfo(f);
    68. fileSize = fi.Length;
    69. file = fi.Name;
    70. }
    71. public override string ToString()
    72. {
    73. string text = string.Format("{0}: time = {1:0} ms, size = {2}", file, milliSeconds, fileSize);
    74. return text;
    75. }
    76. internal string ToString(long size)
    77. {
    78. string text = string.Format("{0}: time = {1:0} ms, size = {2} Byte, rel size = {3:0.000}", file, milliSeconds, fileSize, (double)fileSize / (double)size);
    79. return text;
    80. }
    81. };
    82. /// <summary>
    83. /// constructor
    84. /// </summary>
    85. public MainWindow()
    86. {
    87. _LogFile1 = _ImagePath1 + "DurationLog.txt";
    88. _LogFile2 = _ImagePath2 + "FileSize.txt";
    89. InitializeComponent();
    90. this.label1.Content = "";
    91. this.label2.Content = "";
    92. this.label3.Content = "";
    93. _Random = new Random();
    94. _Pixels = new ushort[_Height * _Width];
    95. } // MainWindow
    96. /// <summary>
    97. /// Performes the pattern test,
    98. /// showes the log file
    99. /// </summary>
    100. /// <param name="sender"></param>
    101. /// <param name="e"></param>
    102. private void button1_Click(object sender, RoutedEventArgs e)
    103. {
    104. MessageBox.Show("Not more supported.");
    105. return;
    106. // new log instance
    107. System.IO.File.AppendAllText(_LogFile1, "-----------------------------------------" + Environment.NewLine);
    108. System.IO.File.AppendAllText(_LogFile1, string.Format("Width = {0}, Height = {1} ({2} MB){3}", _Width, _Height, 2 * _Width * _Height / 1024.0 / 1024.0, Environment.NewLine));
    109. for (int pattern = 0; pattern < 8; pattern++)
    110. {
    111. performEncoding(pattern);
    112. checkDecoding(pattern);
    113. }
    114. // open logfile with notepad
    115. Process.Start(_LogFile1);
    116. } // button1_Click
    117. /// <summary>
    118. /// converts all PNG and JPG images in the predefined folder to wdp format,
    119. /// showes the log file.
    120. /// </summary>
    121. /// <param name="sender"></param>
    122. /// <param name="e"></param>
    123. private void button2_Click(object sender, RoutedEventArgs e)
    124. {
    125. MessageBox.Show("Not more supported.");
    126. return;
    127. // new log instance
    128. System.IO.File.AppendAllText(_LogFile2, "-----------------------------------------" + Environment.NewLine);
    129. foreach (FileInfo fi in new System.IO.DirectoryInfo(_ImagePath2).GetFiles("*.png"))
    130. {
    131. convertImageToWdp(fi);
    132. }
    133. // test: other file format
    134. foreach (FileInfo fi in new System.IO.DirectoryInfo(_ImagePath2).GetFiles("*.jpg"))
    135. {
    136. convertImageToWdp(fi);
    137. }
    138. // open logfile with notepad
    139. Process.Start(_LogFile2);
    140. } // button2_Click
    141. /// <summary>
    142. /// Calculation of the test pattern in order to pattern kind,
    143. /// this procedure is not time optimated.
    144. /// </summary>
    145. /// <param name="pattern">kind of pattern</param>
    146. private void calcPattern(int pattern)
    147. {
    148. for (int y = 0; y < _Height; y++)
    149. {
    150. // start value for chess border line (even or odd)
    151. ushort value = (ushort)(((y & 1) == 1) ? ushort.MaxValue - _RandomRange : _RandomRange);
    152. for (int x = 0; x < _Width; x++)
    153. {
    154. int pixel = 0;
    155. int index = y * _Width + x;
    156. switch (pattern)
    157. {
    158. default: // new pattern kind?
    159. Debug.Assert(false);
    160. goto case 0;
    161. case 0: // vertical grey edge
    162. case 4:
    163. pixel = y << 8;
    164. break;
    165. case 1: // horizontal grey edge
    166. case 5:
    167. pixel = x << 7;
    168. break;
    169. case 2: // diagonal grey edge
    170. case 6:
    171. pixel = (x + y) << 6;
    172. break;
    173. case 3: // 1 pixel chess border
    174. case 7:
    175. pixel = value;
    176. // next chess border field
    177. value = (ushort)(ushort.MaxValue - _RandomRange - value);
    178. break;
    179. }
    180. // generate noise
    181. if ((pattern & 4) == 4)
    182. {
    183. pixel += _Random.Next(_RandomRange);
    184. }
    185. // store pixel info
    186. _Pixels[index] = (ushort)(pixel & 0xFFFF);
    187. }
    188. }
    189. } // calcPattern
    190. /// <summary>
    191. /// reads the lossless comprimated wdp image from disc,
    192. /// and compares the pixel info with the calculated data binary.
    193. /// </summary>
    194. /// <param name="pattern">kind of pattern</param>
    195. private void checkDecoding(int pattern)
    196. {
    197. Stopwatch st = startTimeMeasure();
    198. ushort[] pixels = null;
    199. string file = string.Format(_FmtWdp1, _ImagePath1, pattern);
    200. using (FileStream stream = new FileStream(file, FileMode.Open))
    201. {
    202. // WmpBitmapDecoder(Uri(), ...) claimes the file, that followes an exception in next call of performLosslessWdp()
    203. //WmpBitmapDecoder decoder = new WmpBitmapDecoder(new Uri(file, UriKind.Absolute), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    204. WmpBitmapDecoder decoder = new WmpBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    205. BitmapSource bitmapSource = decoder.Frames[0];
    206. Debug.Assert(bitmapSource.Format == PixelFormats.Gray16);
    207. //// show image
    208. //this.image1.Source = bitmapSource;
    209. pixels = new ushort[bitmapSource.PixelHeight * bitmapSource.PixelWidth];
    210. bitmapSource.CopyPixels(pixels, _Stride, 0);
    211. }
    212. stopTimeAndLog(st, file);
    213. checkDifferences(pixels);
    214. } // checkDecoding
    215. /// <summary>
    216. /// Binary compare of the image information of a file image and the given values.
    217. /// </summary>
    218. /// <param name="pixels">image information of the readed image</param>
    219. /// <returns>identity or not</returns>
    220. private bool checkDifferences(ushort[] pixels)
    221. {
    222. int diff = 0;
    223. for (int i = 0; i < pixels.Length; i++)
    224. {
    225. if (pixels[i] != _Pixels[i])
    226. {
    227. diff++;
    228. }
    229. }
    230. this.label1.Content = string.Format("Differences: {0}", diff);
    231. return diff == 0;
    232. } // checkDifferences
    233. /// <summary>
    234. /// converts the given image file to a 16 bpp gray WDP image file.
    235. /// </summary>
    236. /// <param name="fiIn">FileInfo object of the file to convert</param>
    237. /// <returns>success</returns>
    238. private bool convertImageToWdp(FileInfo fiIn)
    239. {
    240. BitmapImage image = null;
    241. try
    242. {
    243. // accepts (nearly) all kinds of images
    244. image = new BitmapImage(new Uri(fiIn.FullName, UriKind.Absolute));
    245. }
    246. catch (NotSupportedException)
    247. {
    248. // unknown format (e.g. renamed *.cs file)
    249. return false;
    250. }
    251. // target format encoder
    252. WmpBitmapEncoder encoder = new WmpBitmapEncoder();
    253. if (encoder.CodecInfo.SupportsLossless)
    254. {
    255. encoder.Lossless = true;
    256. }
    257. encoder.ImageQualityLevel = 1F; // 0.9F ist standard
    258. // create a 16 bpp gray image frame
    259. if (image.Format != PixelFormats.Gray16)
    260. {
    261. // Image has to be converted to 16 bpp gray
    262. FormatConvertedBitmap newImage = new FormatConvertedBitmap(image, PixelFormats.Gray16, null, 0.0);
    263. encoder.Frames.Add(BitmapFrame.Create(newImage));
    264. }
    265. else
    266. {
    267. encoder.Frames.Add(BitmapFrame.Create(image));
    268. }
    269. FileInfo fiOut = createFileInfo(fiIn);
    270. using (FileStream streamOut = new FileStream(fiOut.FullName, FileMode.Create))
    271. {
    272. encoder.Save(streamOut);
    273. }
    274. string text = string.Format("{0} - {1} ==> {2}", fiIn.Name, fiIn.Length, fiOut.Length);
    275. System.IO.File.AppendAllText(_LogFile2, text + Environment.NewLine);
    276. return true;
    277. } // convertImageToWdp
    278. /// <summary>
    279. /// creates a FileInfo object depending on the given one:
    280. /// c:\xxx\yyy\aaa.bbb ==> c:\xxx\yyy\wdp\aaa.wdp
    281. /// </summary>
    282. /// <param name="fiIn">file in information</param>
    283. /// <returns></returns>
    284. private static FileInfo createFileInfo(FileInfo fiIn)
    285. {
    286. DirectoryInfo diOut = fiIn.Directory;
    287. // insert a WDP folder
    288. string fileOut = diOut.ToString() + @"\wdp\";
    289. Directory.CreateDirectory(fileOut);
    290. fileOut += fiIn.Name.Replace(fiIn.Extension, ".wdp");
    291. FileInfo fiOut = new FileInfo(fileOut);
    292. return fiOut;
    293. } // createFileInfo
    294. /// <summary>
    295. /// test routine for several encoding types:
    296. /// - losless and lossy WDP images,
    297. /// - standard JPG images,
    298. /// - uncompressed TIFF images.
    299. /// Conversion Time and File size of the losless WDP image will be logged.
    300. /// </summary>
    301. /// <param name="pattern">kind of pattern</param>
    302. private void performEncoding(int pattern)
    303. {
    304. calcPattern(pattern);
    305. // Creates an image with the pre-defined pattern
    306. BitmapSource image = BitmapSource.Create(
    307. _Width, _Height,
    308. 96, 96,
    309. PixelFormats.Gray16,
    310. null, // BitmapPalettes.Gray16,
    311. _Pixels,
    312. _Stride);
    313. performLosslessWdp(image, string.Format(_FmtWdp1, _ImagePath1, pattern), pattern);
    314. performLossyWdp(image, string.Format(_FmtWdp2, _ImagePath1, pattern));
    315. performUncompressedTiff(image, string.Format(_FmtTiff, _ImagePath1, pattern));
    316. performStandardJpeg(image, string.Format(_FmtJpeg, _ImagePath1, pattern), 75);
    317. } // performEncoding
    318. /// <summary>
    319. /// lossless WMP format
    320. /// </summary>
    321. /// <param name="image"></param>
    322. /// <param name="file"></param>
    323. /// <param name="pattern">neccessary for duration protocol</param>
    324. private void performLosslessWdp(BitmapSource image, string file, int pattern)
    325. {
    326. Stopwatch st = startTimeMeasure();
    327. using (FileStream stream = new FileStream(file, FileMode.Create))
    328. {
    329. WmpBitmapEncoder encoder = new WmpBitmapEncoder();
    330. if (encoder.CodecInfo.SupportsLossless)
    331. {
    332. encoder.Lossless = true;
    333. }
    334. encoder.ImageQualityLevel = 1F; // 0.9F ist standard
    335. encoder.Frames.Add(BitmapFrame.Create(image));
    336. encoder.Save(stream);
    337. }
    338. stopTimeAndLog(st, pattern);
    339. } // performLosslessWdp
    340. /// <summary>
    341. /// lossy WMP format
    342. /// </summary>
    343. /// <param name="image"></param>
    344. /// <param name="file"></param>
    345. private MethodMark performLossyWdp(BitmapSource image, string file, BitmapMetadata meta = null)
    346. {
    347. Stopwatch stw = new Stopwatch();
    348. stw.Start();
    349. using (FileStream stream = new FileStream(file, FileMode.Create))
    350. {
    351. WmpBitmapEncoder encoder = new WmpBitmapEncoder();
    352. encoder.Lossless = false;
    353. encoder.ImageQualityLevel = 0.8F; // standard: 0.9F
    354. if (meta == null)
    355. {
    356. encoder.Frames.Add(BitmapFrame.Create(image));
    357. }
    358. else
    359. {
    360. encoder.Frames.Add(BitmapFrame.Create(image, null, meta, null));
    361. }
    362. encoder.Save(stream);
    363. }
    364. stw.Stop();
    365. return new MethodMark(file, stw);
    366. } // performLossyWdp
    367. private MethodMark performLossyWdp(BitmapSource image, string file, int quality, BitmapMetadata meta = null)
    368. {
    369. Stopwatch stw = new Stopwatch();
    370. stw.Start();
    371. using (FileStream stream = new FileStream(file, FileMode.Create))
    372. {
    373. WmpBitmapEncoder encoder = new WmpBitmapEncoder();
    374. encoder.Lossless = false;
    375. encoder.ImageQualityLevel = quality / 100F; // standard: 0.9F
    376. if (meta == null)
    377. {
    378. encoder.Frames.Add(BitmapFrame.Create(image));
    379. }
    380. else
    381. {
    382. encoder.Frames.Add(BitmapFrame.Create(image, null, meta, null));
    383. }
    384. encoder.Save(stream);
    385. }
    386. stw.Stop();
    387. return new MethodMark(file, stw);
    388. } // performLossyWdp
    389. /// <summary>
    390. /// standard JPEG format
    391. /// </summary>
    392. /// <param name="image"></param>
    393. /// <param name="file"></param>
    394. private void performStandardJpeg(BitmapSource image, string file, int level)
    395. {
    396. using (FileStream stream = new FileStream(file, FileMode.Create))
    397. {
    398. JpegBitmapEncoder encoder = new JpegBitmapEncoder();
    399. encoder.QualityLevel = level; // standard: 75
    400. encoder.Frames.Add(BitmapFrame.Create(image));
    401. encoder.Save(stream);
    402. }
    403. }
    404. /// <summary>
    405. /// uncompressed TIFF format
    406. /// </summary>
    407. /// <param name="image"></param>
    408. /// <param name="file"></param>
    409. private void performUncompressedTiff(BitmapSource image, string file, BitmapMetadata metadata = null)
    410. {
    411. using (FileStream stream = new FileStream(file, FileMode.Create))
    412. {
    413. TiffBitmapEncoder encoder = new TiffBitmapEncoder();
    414. encoder.Compression = TiffCompressOption.None;
    415. if (metadata == null)
    416. {
    417. encoder.Frames.Add(BitmapFrame.Create(image));
    418. }
    419. else
    420. {
    421. //Create(image, BitmapSource thumbnail, BitmapMetadata metadata, ReadOnlyCollection<ColorContext> colorContexts);
    422. encoder.Frames.Add(BitmapFrame.Create(image, null, metadata, null));
    423. }
    424. encoder.Save(stream);
    425. }
    426. } // performUncompressedTiff
    427. /// <summary>
    428. /// creates ans starts a new Stopwatch instance
    429. /// </summary>
    430. /// <returns></returns>
    431. private Stopwatch startTimeMeasure()
    432. {
    433. return Stopwatch.StartNew();
    434. } // startTimeMeasure
    435. /// <summary>
    436. /// stops the Stopwatch instance and logs the elapsed time
    437. /// </summary>
    438. /// <param name="st"></param>
    439. /// <param name="pattern">kind of pattern</param>
    440. private void stopTimeAndLog(Stopwatch st, int pattern)
    441. {
    442. st.Stop();
    443. string text = string.Format("Pattern: {0}, Encoding: {1:0} ms", pattern, st.ElapsedMilliseconds);
    444. this.label2.Content = text;
    445. System.IO.File.AppendAllText(_LogFile1, text + " ");
    446. } // stopTimeMeasure
    447. /// <summary>
    448. /// stops the Stopwatch instance and logs the elapsed time, and file length
    449. /// </summary>
    450. /// <param name="st"></param>
    451. /// <param name="file">file name to get its length</param>
    452. private void stopTimeAndLog(Stopwatch st, string file)
    453. {
    454. st.Stop();
    455. System.IO.FileInfo fi = new FileInfo(file);
    456. string text = string.Format("Decoding: {0:0} ms, Filesize = {1}", st.ElapsedMilliseconds, fi.Length);
    457. this.label3.Content = text;
    458. System.IO.File.AppendAllText(_LogFile1, text + Environment.NewLine);
    459. } // stopTimeMeasure
    460. private void button3_Click(object sender, RoutedEventArgs e)
    461. {
    462. Cursor = Cursors.Wait;
    463. int index = 0;
    464. string path = @"C:\Temp\Komprimierung\AnteriorSegment";//WhiteToWhite";//Sclera";//Retina";//Keratometry2";//
    465. List<string> todo = new List<string>() { path, "compression" };
    466. System.IO.File.WriteAllLines(@"C:\Temp\Komprimierung\todo.txt", todo.ToArray());
    467. foreach (string file in System.IO.Directory.GetFiles(path, "*.Png", SearchOption.TopDirectoryOnly))
    468. {
    469. createLossyWdpImages(file, index);
    470. index++;
    471. }
    472. Cursor = Cursors.Arrow;
    473. } // button3_Click
    474. private void createLossyWdpImages(string path, int index)
    475. {
    476. BitmapImage image = null;
    477. //string _LogFile3 = string.Format(@"C:\Temp\Komprimierung\FileSize_{0:00}.txt", index);
    478. FileInfo fiIn = new FileInfo(path);
    479. try
    480. {
    481. // accepts (nearly) all kinds of images
    482. image = new BitmapImage(new Uri(path, UriKind.Absolute));
    483. }
    484. catch (NotSupportedException)
    485. {
    486. // unknown format (e.g. renamed *.cs file)
    487. return;
    488. }
    489. int[] quality = { 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100 };
    490. FileInfo fi = new FileInfo(path);
    491. string pathOut = fi.DirectoryName + "\\" + index.ToString("00");
    492. Directory.CreateDirectory(pathOut);
    493. _LogFile3 = pathOut + "\\xxx.txt";
    494. System.IO.File.Delete(_LogFile3);
    495. string path2 = pathOut + "\\" + fi.Name;
    496. path2 = path2.Substring(0, path2.LastIndexOf('.')) + "_";
    497. foreach (int q in quality)
    498. {
    499. //string path3 = path2 + i.ToString("000") + ".jpg";
    500. //performStandardJpeg(image, path3, i);
    501. string path4 = path2 + q.ToString("000") + ".wdp";
    502. performLossyWdp(image, path4, q);
    503. calcDifferences(image, path4);
    504. }
    505. }
    506. private void calcDifferences(BitmapImage imageOri, string pathToComp)
    507. {
    508. PixelFormat fmt = imageOri.Format;
    509. Debug.Assert(fmt == PixelFormats.Bgr32 || fmt == PixelFormats.Bgra32);
    510. BitmapImage imageCmp = null;
    511. imageCmp = new BitmapImage(new Uri(pathToComp, UriKind.RelativeOrAbsolute));
    512. int nStride = (imageOri.PixelWidth * imageOri.Format.BitsPerPixel + 7) / 8;
    513. byte[] arrOri = new byte[imageOri.PixelHeight * nStride];
    514. byte[] arrCmp = new byte[imageOri.PixelHeight * nStride];
    515. imageOri.CopyPixels(arrOri, nStride, 0);
    516. imageCmp.CopyPixels(arrCmp, nStride, 0);
    517. int max = 0;
    518. long summe = 0;
    519. // start nicht bei a, sondern bei b,g,r
    520. int start = (imageOri.Format.BitsPerPixel >= 24) ? 1 : 0;
    521. for (int i = start; i < arrOri.Length; i += imageOri.Format.BitsPerPixel / 8)
    522. {
    523. int diff = Math.Abs(arrOri[i] - arrCmp[i]);
    524. max = Math.Max(diff, max);
    525. summe += diff;
    526. }
    527. FileInfo fi2 = new FileInfo(pathToComp);
    528. string txt = String.Format("{3}\t - Max Diff = {0}, Diff-Vol = {1}, size = {2}{4}", max, summe, fi2.Length, pathToComp, Environment.NewLine);
    529. System.IO.File.AppendAllText(_LogFile3, txt);
    530. }
    531. private static Action EmptyDelegate = delegate() { };
    532. private void button4_Click(object sender, RoutedEventArgs e)
    533. {
    534. Cursor = Cursors.Wait;
    535. string[] localpath = { "AnteriorSegment", "WhiteToWhite", "Sclera", "Retina", "Keratometry2", "Keratometry" };
    536. string path = @"C:\Temp\Komprimierung\";
    537. foreach (string folder in localpath)
    538. {
    539. label4.Content = folder;
    540. label4.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
    541. System.Threading.Thread.Sleep(10);
    542. //DispatcherFrame df = new DispatcherFrame(true);
    543. //df.Continue = false;
    544. //Dispatcher.PushFrame(df);
    545. ////label4.Dispatcher.BeginInvoke(((Action)(() => { })));
    546. benchmark(path + folder);
    547. }
    548. Cursor = Cursors.Arrow;
    549. label4.Content = "feddich";
    550. }
    551. private void benchmark(string path)
    552. {
    553. int index = 0;
    554. List<string> todo = new List<string>() { path, "benchmark" };
    555. System.IO.File.WriteAllLines(@"C:\Temp\Komprimierung\todo.txt", todo.ToArray());
    556. string path4;
    557. foreach (string file in System.IO.Directory.GetFiles(path, "*.Png", SearchOption.TopDirectoryOnly))
    558. {
    559. MethodMark mm = null;
    560. BitmapImage image = new BitmapImage(new Uri(file, UriKind.Absolute));
    561. FileInfo fiOri = new FileInfo(file);
    562. string pathOut = path + "\\_wdp_tiff\\" + index.ToString("00");
    563. Directory.CreateDirectory(pathOut);
    564. _LogFile3 = pathOut + "\\xxx.txt";
    565. System.IO.File.Delete(_LogFile3);
    566. System.IO.File.AppendAllText(_LogFile3, String.Format("Ori-Length = {0}{1}", fiOri.Length, Environment.NewLine));
    567. path4 = pathOut + "\\" + fiOri.Name + ".wdp";
    568. mm = performLossyWdp(image, path4, 80); // vorgegebener Wert
    569. System.IO.File.AppendAllText(_LogFile3, mm.ToString(fiOri.Length) + Environment.NewLine);
    570. path4 = pathOut + "\\" + fiOri.Name;
    571. for (int tiffComp = 0; tiffComp <= 6; tiffComp++)
    572. {
    573. mm = createTiffImage(image, path4, tiffComp);
    574. if (mm != null) // nicht Ccitt3, Ccitt4 (1 BPP)
    575. {
    576. System.IO.File.AppendAllText(_LogFile3, mm.ToString(fiOri.Length) + Environment.NewLine);
    577. }
    578. }
    579. index++;
    580. }
    581. }
    582. private MethodMark createTiffImage(BitmapImage image, string path, int index)
    583. {
    584. Debug.Assert(index >= 0 && index <= 6);
    585. TiffCompressOption comp = (TiffCompressOption)index;
    586. if (comp == TiffCompressOption.Ccitt3 || comp == TiffCompressOption.Ccitt4) // 1 BPP
    587. {
    588. return null;
    589. }
    590. Stopwatch stw = new Stopwatch();
    591. stw.Start();
    592. string fileOut = path + "_" + comp.ToString() + ".tiff";
    593. using (FileStream stream = new FileStream(fileOut, FileMode.Create))
    594. {
    595. TiffBitmapEncoder encoder = new TiffBitmapEncoder();
    596. encoder.Compression = comp;
    597. // create a 8 bpp gray image frame
    598. if (image.Format != PixelFormats.Gray8)
    599. {
    600. // Image has to be converted to 16 bpp gray
    601. FormatConvertedBitmap newImage = new FormatConvertedBitmap(image, PixelFormats.Gray8, null, 0.0);
    602. encoder.Frames.Add(BitmapFrame.Create(newImage));
    603. }
    604. else
    605. {
    606. encoder.Frames.Add(BitmapFrame.Create(image));
    607. }
    608. encoder.Save(stream);
    609. }
    610. stw.Stop();
    611. return new MethodMark(fileOut, stw);
    612. }
    613. private void button5_Click(object sender, RoutedEventArgs e)
    614. {
    615. string file = @"C:\Temp\Komprimierung\_Metadaten\default_0.png";
    616. BitmapImage image = new BitmapImage(new Uri(file, UriKind.Absolute));
    617. saveMetadataImage(ImageFormats.tiff, file, image);
    618. readMetadata(file + ".tiff");
    619. }
    620. private void button6_Click(object sender, RoutedEventArgs e)
    621. {
    622. string file = @"C:\Temp\Komprimierung\_Metadaten\default_0.png";
    623. BitmapImage image = new BitmapImage(new Uri(file, UriKind.Absolute));
    624. saveMetadataImage(ImageFormats.wdp, file, image);
    625. readMetadata(file + ".wdp");
    626. }
    627. /// <summary>
    628. /// Auslesen und Anzeigen von Metadaten aus einem vorgegebenen File
    629. /// </summary>
    630. /// <param name="file">Pfad der Bilddatei</param>
    631. private void readMetadata(string file)
    632. {
    633. BitmapSource image = BitmapFrame.Create(new Uri(file, UriKind.Absolute));
    634. BitmapMetadata meta = image.Metadata as BitmapMetadata;
    635. if (meta == null)
    636. {
    637. label5.Content = "No Metadata available";
    638. label6.Content = "";
    639. label7.Content = "";
    640. label8.Content = "";
    641. }
    642. else
    643. {
    644. label5.Content = meta.DateTaken;
    645. label7.Content = meta.Subject;
    646. label8.Content = meta.Format;
    647. if (meta.Keywords != null && meta.Keywords.Count >= 1)
    648. {
    649. label6.Content = meta.Keywords[0];
    650. }
    651. else
    652. {
    653. label6.Content = "no Keywords available";
    654. }
    655. }
    656. image = null;
    657. GC.Collect(); // to dispose image
    658. }
    659. /// <summary>
    660. /// Speichern eines Images unter einem vorgegebenen Format mit (künstlichen) Metadaten
    661. /// </summary>
    662. /// <param name="imageFormats">Zielbildformat</param>
    663. /// <param name="file">Pfad ohne Externsion</param>
    664. /// <param name="image">Bildinformation</param>
    665. private void saveMetadataImage(ImageFormats imageFormats, string file, BitmapImage image)
    666. {
    667. switch (imageFormats)
    668. {
    669. case ImageFormats.tiff:
    670. performUncompressedTiff(image, file + ".tiff", CreateMetadata("tiff"));
    671. break;
    672. case ImageFormats.wdp:
    673. performLossyWdp(image, file + ".wdp", CreateMetadata("wmphoto"));
    674. break;
    675. default:
    676. Debug.Assert(false, "unknown imageFormat");
    677. break;
    678. }
    679. //BitmapFrame thumb = BitmapFrame.Create(new Uri(file, UriKind.Absolute));
    680. //performLossyWdp(thumb.Thumbnail, file + ".thumb.wdp");
    681. }
    682. /// <summary>
    683. /// Generierung von irgend Metadaten im vorgegebenen Container-Format
    684. /// </summary>
    685. /// <param name="containerFormat"></param>
    686. /// <returns></returns>
    687. private BitmapMetadata CreateMetadata(string containerFormat)
    688. {
    689. BitmapMetadata metaWmp = new BitmapMetadata(containerFormat);
    690. metaWmp.Comment = "Test Metadata " + containerFormat; // Unicode
    691. // Datum und Uhrzeit im amerikanischen Format, wird überprüft, AM, PM wird aufgelöst
    692. // 15.11.2012 wirft eine Exception
    693. string date = DateTime.Now.ToString(new System.Globalization.CultureInfo("en-US"));
    694. metaWmp.DateTaken = date; // ANSI !!!!!
    695. metaWmp.Subject = "Franz Müller"; // Unicode
    696. metaWmp.Title = "Kind Of Image"; // Unicode
    697. List<string> Keywords = new List<string>();// { "bla", "blabla" };
    698. Keywords.Add("Resolution x = 12,34 mue"); // wdp: ANSI, Tiff: ANSI und Unicode
    699. Keywords.Add("Resolution y = 56.78 mue"); // wdp: ANSI, Tiff: ANSI und Unicode
    700. metaWmp.Keywords = new ReadOnlyCollection<string>(Keywords);
    701. return metaWmp;
    702. }
    703. private void button7_Click(object sender, RoutedEventArgs e)
    704. {
    705. string file = @"C:\Temp\Komprimierung\_Metadaten\default_0.png.tiff"; // wdp"; //
    706. //BitmapImage image = new BitmapImage(new Uri(file, UriKind.Absolute));
    707. BitmapSource image = BitmapFrame.Create(new Uri(file, UriKind.Absolute));
    708. // Metadata vorhanden
    709. using (FileStream stream = new FileStream(file + ".wdp", FileMode.Create))
    710. {
    711. WmpBitmapEncoder encoder = new WmpBitmapEncoder();
    712. // die Metadata gehen hier bei Formatwechsel verloren !!! (tiff <==> wdp)
    713. encoder.Frames.Add(BitmapFrame.Create(image, null, (BitmapMetadata)image.Metadata, null));
    714. encoder.Save(stream);
    715. }
    716. readMetadata(file + ".wdp");
    717. }
    718. }
    719. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Peter329

    Hier noch ein kleiner Vorschlag zum GDI+ Fehler

    Ist ungetestet, habe es nur kurz runtergeschrieben.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Imports System.IO
    4. Imports System.Text
    5. Imports System.Drawing
    6. Imports System.Drawing.Imaging
    7. 'Die OriginalDatei (Filename & ".jpg") könnte überschrieben werden.
    8. Public Module Vorschlag
    9. Private ReadOnly Filename As String = "pic1"
    10. Public Sub Main()
    11. Dim rawformat As ImageFormat
    12. Dim orgwidth, orgheight As Int32
    13. Using orgimg = GetFileImg(Filename & ".jpg")
    14. rawformat = orgimg.RawFormat
    15. orgwidth = orgimg.Width : orgheight = orgimg.Height
    16. Using rotateimg = RotateImage(orgimg, 72.0F)
    17. rotateimg.Save(Filename & 2.ToString & ".jpg", ImageFormat.Jpeg)
    18. If SaveFile(Encrypt(ToByteArrMs(rotateimg)), Filename) Then
    19. 'weiterer Code
    20. End If
    21. End Using
    22. End Using
    23. Using tmpimg = ToBitmapIC(Decrypt(LoadFile(Filename)))
    24. File.Delete(Filename) ': File.Delete(Filename & ".jpg")
    25. Using newrotateimg = RotateImage(tmpimg, -72.0F)
    26. Dim w = (newrotateimg.Width - orgwidth) / 2.0F
    27. Dim h = (newrotateimg.Height - orgheight) / 2.0F
    28. Using newimg = Correction(newrotateimg, orgwidth, orgheight, w, h)
    29. newimg.Save(Filename & "New" & ".jpg", rawformat)
    30. End Using
    31. End Using
    32. End Using
    33. End Sub
    34. Private Function Correction(img As Bitmap,
    35. newwidth As Int32,
    36. newheight As Int32,
    37. w As Single,
    38. h As Single) As Bitmap
    39. If img Is Nothing Then Throw New ArgumentNullException("image")
    40. Using newimg As New Bitmap(newwidth, newheight)
    41. Using g = Graphics.FromImage(newimg)
    42. g.DrawImage(img, New PointF(-w, -h))
    43. g.Dispose()
    44. img.Dispose()
    45. Return CloneImage(newimg)
    46. End Using
    47. End Using
    48. End Function
    49. Private Function CloneImage(img As Bitmap) As Bitmap
    50. 'Vorteil: Ist garantiert ein richtiger Clone
    51. Dim ic = New ImageConverter
    52. Dim b = DirectCast(ic.ConvertTo(img, GetType(Byte())), Byte())
    53. ic = New ImageConverter
    54. Return DirectCast(ic.ConvertFrom(b), Bitmap)
    55. End Function
    56. Private Function GetFileImg(filename As String) As Bitmap
    57. Dim buffer() As Byte
    58. Using fs As New FileStream(filename, FileMode.Open, FileAccess.Read)
    59. Dim len = CInt(fs.Length)
    60. buffer = New Byte(len - 1I) {}
    61. fs.Read(buffer, 0, len)
    62. End Using
    63. If buffer IsNot Nothing AndAlso buffer.Length > 1 Then
    64. Dim ic As New ImageConverter
    65. Return DirectCast(ic.ConvertFrom(buffer), Bitmap)
    66. End If
    67. Return Nothing
    68. End Function
    69. Private Function SaveFile(b() As Byte, filename As String) As Boolean
    70. Using sw = New StreamWriter(filename)
    71. sw.WriteLine(Encoding.UTF8.GetString(b))
    72. Return True
    73. End Using
    74. Return False
    75. End Function
    76. Private Function LoadFile(filename As String) As Byte()
    77. Dim buffer() As Byte
    78. Using fs As New FileStream(filename, FileMode.Open, FileAccess.Read)
    79. Dim len = CInt(fs.Length)
    80. buffer = New Byte(len - 1I) {}
    81. fs.Read(buffer, 0, len)
    82. End Using
    83. Return buffer
    84. End Function
    85. Private Function Encrypt(b() As Byte) As Byte()
    86. 'Irgend eine Vercryptung. Probeweise nehm ich hier B64
    87. Return Encoding.UTF8.GetBytes(Convert.ToBase64String(b))
    88. End Function
    89. Private Function Decrypt(b() As Byte) As Byte()
    90. Return Convert.FromBase64String(Encoding.UTF8.GetString(b))
    91. End Function
    92. Private Function ToByteArrMs(ByVal img As Bitmap) As Byte()
    93. Dim res() As Byte
    94. Using ms = New MemoryStream
    95. Using cimg = CloneImage(img)
    96. cimg.Save(ms, ImageFormat.Jpeg)
    97. res = ms.ToArray
    98. End Using
    99. End Using
    100. Return res
    101. End Function
    102. Private Function ToBitmapIC(ByVal bimg() As Byte) As Bitmap
    103. If bimg IsNot Nothing AndAlso bimg.Length > 0 Then
    104. Dim ic As New ImageConverter
    105. Return CType(ic.ConvertFrom(bimg), Bitmap)
    106. End If
    107. Return Nothing
    108. End Function
    109. Private Function RotateImage(bmp As Bitmap, angle As Single) As Bitmap
    110. If bmp Is Nothing Then Throw New ArgumentNullException("image")
    111. Dim rad = angle * Math.PI / 180.0R
    112. Dim cos = Math.Abs(Math.Cos(rad)), sin = Math.Abs(Math.Sin(rad))
    113. Dim newWidth = CInt(Math.Ceiling(bmp.Width * cos + bmp.Height * sin))
    114. Dim newHeight = CInt(Math.Ceiling(bmp.Width * sin + bmp.Height * cos))
    115. Using newimg = DirectCast(New Bitmap(newWidth, newHeight).Clone, Bitmap)
    116. Using g As Graphics = Graphics.FromImage(newimg)
    117. g.TranslateTransform(newWidth / 2.0F, newHeight / 2.0F)
    118. g.RotateTransform(angle)
    119. g.TranslateTransform(-bmp.Width / 2.0F, -bmp.Height / 2.0F)
    120. g.DrawImage(bmp, New Point(0, 0))
    121. Return CloneImage(newimg)
    122. End Using
    123. End Using
    124. End Function
    125. End Module


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    exc-jdbi schrieb:

    Hier noch ein kleiner Vorschlag zum GDI+ Fehler
    Was meinst Du damit? Der Code sieht - umfangreich aus. Deine Antwort impliziert aber irgendwie, dass nur so der GDI+-Fehler ... ja, was? Behoben wird? Umgangen wird?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.