1 /******************************************************************************
2  * $Id: GDALAdjustContrast.cs f070adf64950cae1c6cc86b104ba835c29df06b1 2016-08-28 06:06:11Z Kurt Schwehr $
3  *
4  * Name:     GDALAdjustContrast.cs
5  * Project:  GDAL CSharp Interface
6  * Purpose:  A sample app to demonstrate how to read the dataset into the
7  *           memory, adjust the contrast of the image and write back to the
8  *           dataset persistently.
9  * Author:   Tamas Szekeres, szekerest@gmail.com
10  *
11  ******************************************************************************
12  * Copyright (c) 2007, Tamas Szekeres
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included
22  * in all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30  * DEALINGS IN THE SOFTWARE.
31  *****************************************************************************/
32 
33 using System;
34 using System.Drawing;
35 using System.Drawing.Imaging;
36 using System.Drawing.Drawing2D;
37 using OSGeo.GDAL;
38 
39 /**
40  * <p>Title: GDAL C# GDALAdjustContrast example.</p>
41  * <p>Description: A sample app to demonstrate how to read the dataset into the
42  * memory, adjust the contrast of the image and write back to the dataset persistently.</p>
43  * @author Tamas Szekeres (szekerest@gmail.com)
44  * @version 1.0
45  */
46 
47 
48 
49 /// <summary>
50 /// A sample app to demonstrate how to read the dataset into the
51 /// memory, adjust the contrast of the image and write back to the dataset persistently.
52 /// </summary>
53 
54 class GDALAdjustContrast {
55 
usage()56 	public static void usage()
57 
58 	{
59         Console.WriteLine("usage: GDALAdjustContrast {dataset name} {contrast ratio}");
60 		System.Environment.Exit(-1);
61 	}
62 
63 
64     // bitmap parameters
65     static int[] bandMap;
66     static ColorTable ct;
67     static int channelCount;
68     static bool hasAlpha;
69     static bool isPremultiplied;
70     static bool isIndexed;
71     static int channelSize;
72     static PixelFormat pixelFormat;
73     static DataType dataType;
74     static int pixelSpace;
75 
Main(string[] args)76     public static void Main(string[] args)
77     {
78 
79         if (args.Length != 2) usage();
80 
81         // Using early initialization of System.Console
82         Console.WriteLine("Adjusting the image: " + args[0]);
83 
84         try
85         {
86             float contrastRatio = float.Parse(args[1]);
87             /* -------------------------------------------------------------------- */
88             /*      Register driver(s).                                             */
89             /* -------------------------------------------------------------------- */
90             Gdal.AllRegister();
91 
92             /* -------------------------------------------------------------------- */
93             /*      Open dataset.                                                   */
94             /* -------------------------------------------------------------------- */
95             Dataset ds = Gdal.Open(args[0], Access.GA_Update);
96 
97             if (ds == null)
98             {
99                 Console.WriteLine("Can't open " + args[0]);
100                 System.Environment.Exit(-1);
101             }
102 
103             Bitmap bmp = CreateCompatibleBitmap(ds, ds.RasterXSize, ds.RasterYSize);
104             LoadBitmapDirect(ds, bmp, 0, 0, ds.RasterXSize, ds.RasterYSize, ds.RasterXSize, ds.RasterYSize, 0);
105             Bitmap newBitmap = (Bitmap)bmp.Clone();
106 
107             //create the ColorMatrix
108             float[][] colormatrix = new float[][]
109               {
110                  new float[] {contrastRatio, 0, 0, 0, 0},
111                  new float[] {0, contrastRatio, 0, 0, 0},
112                  new float[] {0, 0, contrastRatio, 0, 0},
113                  new float[] {0, 0, 0, 1, 0},
114                  new float[] {0, 0, 0, 0, 1}
115               };
116             ColorMatrix colorMatrix = new ColorMatrix(colormatrix);
117 
118             //create the image attributes
119             ImageAttributes attributes = new ImageAttributes();
120 
121             //set the color matrix attribute
122             attributes.SetColorMatrix(colorMatrix);
123 
124             //get a graphics object from the new image
125             Graphics g = Graphics.FromImage(newBitmap);
126             //draw the original image on the new image
127             g.DrawImage(bmp,
128                new Rectangle(0, 0, bmp.Width, bmp.Height),
129                0, 0, bmp.Width, bmp.Height,
130                GraphicsUnit.Pixel, attributes);
131 
132             SaveBitmapDirect(ds, newBitmap, 0, 0, ds.RasterXSize, ds.RasterYSize, ds.RasterXSize, ds.RasterYSize);
133 
134             ds.FlushCache();
135 
136         }
137         catch (Exception e)
138         {
139             Console.WriteLine("Application error: " + e.Message);
140         }
141     }
142 
CreateCompatibleBitmap(Dataset ds, int imageWidth, int imageHeight)143     private static Bitmap CreateCompatibleBitmap(Dataset ds, int imageWidth, int imageHeight)
144     {
145         if (ds.RasterCount == 0)
146             return null;
147 
148         bandMap = new int[4] { 1, 1, 1, 1 };
149         channelCount = 1;
150         hasAlpha = false;
151         isPremultiplied = false;
152         isIndexed = false;
153         channelSize = 8;
154         // Evaluate the bands and find out a proper image transfer format
155         for (int i = 0; i < ds.RasterCount; i++)
156         {
157             Band band = ds.GetRasterBand(i + 1);
158             if (Gdal.GetDataTypeSize(band.DataType) > 8)
159                 channelSize = 16;
160 
161             // retrieving the premultiplied alpha flag
162             string[] metadata = band.GetMetadata("");
163             for (int iMeta = 0; iMeta < metadata.Length; iMeta++)
164             {
165                 if (metadata[iMeta].StartsWith("PREMULTIPLIED_ALPHA"))
166                     isPremultiplied = true;
167             }
168 
169             switch (band.GetRasterColorInterpretation())
170             {
171                 case ColorInterp.GCI_AlphaBand:
172                     channelCount = 4;
173                     hasAlpha = true;
174                     bandMap[3] = i + 1;
175                     break;
176                 case ColorInterp.GCI_BlueBand:
177                     if (channelCount < 3)
178                         channelCount = 3;
179                     bandMap[0] = i + 1;
180                     break;
181                 case ColorInterp.GCI_RedBand:
182                     if (channelCount < 3)
183                         channelCount = 3;
184                     bandMap[2] = i + 1;
185                     break;
186                 case ColorInterp.GCI_GreenBand:
187                     if (channelCount < 3)
188                         channelCount = 3;
189                     bandMap[1] = i + 1;
190                     break;
191                 case ColorInterp.GCI_PaletteIndex:
192                     ct = band.GetRasterColorTable();
193                     isIndexed = true;
194                     bandMap[0] = i + 1;
195                     break;
196                 case ColorInterp.GCI_GrayIndex:
197                     isIndexed = true;
198                     bandMap[0] = i + 1;
199                     break;
200                 default:
201                     // we create the bandmap using the dataset ordering by default
202                     if (i < 4 && bandMap[i] == 0)
203                     {
204                         if (channelCount < i)
205                             channelCount = i;
206                         bandMap[i] = i + 1;
207                     }
208                     break;
209             }
210         }
211 
212         // find out the pixel format based on the gathered information
213         if (isIndexed)
214         {
215             pixelFormat = PixelFormat.Format8bppIndexed;
216             dataType = DataType.GDT_Byte;
217             pixelSpace = 1;
218         }
219         else
220         {
221             if (channelCount == 1)
222             {
223                 if (channelSize > 8)
224                 {
225                     pixelFormat = PixelFormat.Format16bppGrayScale;
226                     dataType = DataType.GDT_Int16;
227                     pixelSpace = 2;
228                 }
229                 else
230                 {
231                     pixelFormat = PixelFormat.Format24bppRgb;
232                     channelCount = 3;
233                     dataType = DataType.GDT_Byte;
234                     pixelSpace = 3;
235                 }
236             }
237             else
238             {
239                 if (hasAlpha)
240                 {
241                     if (channelSize > 8)
242                     {
243                         if (isPremultiplied)
244                             pixelFormat = PixelFormat.Format64bppArgb;
245                         else
246                             pixelFormat = PixelFormat.Format64bppPArgb;
247                         dataType = DataType.GDT_UInt16;
248                         pixelSpace = 8;
249                     }
250                     else
251                     {
252                         if (isPremultiplied)
253                             pixelFormat = PixelFormat.Format32bppPArgb;
254                         else
255                             pixelFormat = PixelFormat.Format32bppArgb;
256                         dataType = DataType.GDT_Byte;
257                         pixelSpace = 4;
258                     }
259                     channelCount = 4;
260                 }
261                 else
262                 {
263                     if (channelSize > 8)
264                     {
265                         pixelFormat = PixelFormat.Format48bppRgb;
266                         dataType = DataType.GDT_UInt16;
267                         pixelSpace = 6;
268                     }
269                     else
270                     {
271                         pixelFormat = PixelFormat.Format24bppRgb;
272                         dataType = DataType.GDT_Byte;
273                         pixelSpace = 3;
274                     }
275                     channelCount = 3;
276                 }
277             }
278         }
279 
280 
281         // Create a Bitmap to store the GDAL image in
282         return new Bitmap(imageWidth, imageHeight, pixelFormat);
283     }
284 
LoadBitmapDirect(Dataset ds, Bitmap bitmap, int xOff, int yOff, int width, int height, int imageWidth, int imageHeight, int iOverview)285     private static void LoadBitmapDirect(Dataset ds, Bitmap bitmap, int xOff, int yOff, int width, int height, int imageWidth, int imageHeight, int iOverview)
286     {
287         if (isIndexed)
288         {
289             // setting up the color table
290             if (ct != null)
291             {
292                 int iCol = ct.GetCount();
293                 ColorPalette pal = bitmap.Palette;
294                 for (int i = 0; i < iCol; i++)
295                 {
296                     ColorEntry ce = ct.GetColorEntry(i);
297                     pal.Entries[i] = Color.FromArgb(ce.c4, ce.c1, ce.c2, ce.c3);
298                 }
299                 bitmap.Palette = pal;
300             }
301             else
302             {
303                 // grayscale
304                 ColorPalette pal = bitmap.Palette;
305                 for (int i = 0; i < 256; i++)
306                     pal.Entries[i] = Color.FromArgb(255, i, i, i);
307                 bitmap.Palette = pal;
308             }
309         }
310 
311         // Use GDAL raster reading methods to read the image data directly into the Bitmap
312         BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, imageWidth, imageHeight), ImageLockMode.ReadWrite, pixelFormat);
313 
314         try
315         {
316             int stride = bitmapData.Stride;
317             IntPtr buf = bitmapData.Scan0;
318 
319             ds.ReadRaster(xOff, yOff, width, height, buf, imageWidth, imageHeight, dataType,
320                 channelCount, bandMap, pixelSpace, stride, 1);
321         }
322         finally
323         {
324             bitmap.UnlockBits(bitmapData);
325         }
326     }
327 
SaveBitmapDirect(Dataset ds, Bitmap bitmap, int xOff, int yOff, int width, int height, int imageWidth, int imageHeight)328     private static void SaveBitmapDirect(Dataset ds, Bitmap bitmap, int xOff, int yOff, int width, int height, int imageWidth, int imageHeight)
329     {
330         if (bitmap != null)
331         {
332             if (isIndexed)
333             {
334                 // TODO: setting up the color table
335             }
336 
337             // Use GDAL writing method to write the image data directly from the Bitmap
338             BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, imageWidth, imageHeight), ImageLockMode.ReadWrite, pixelFormat);
339 
340             try
341             {
342                 int stride = bitmapData.Stride;
343                 IntPtr buf = bitmapData.Scan0;
344 
345                 ds.WriteRaster(xOff, yOff, width, height, buf, imageWidth, imageHeight, dataType,
346                     channelCount, bandMap, pixelSpace, stride, 1);
347             }
348             finally
349             {
350                 bitmap.UnlockBits(bitmapData);
351             }
352         }
353     }
354 }