<div dir="ltr">Even, thanks for the reply and for pointing out the dataset version of <span style="font-family:arial,sans-serif;font-size:13px">RasterIO().</span><div><br></div><div>But I still don't understand a few things. The main one is that you say:</div><div><br></div><div><span style="font-family:arial,sans-serif;font-size:13px">>>> Regarding color space conversions, GDAL generally doesn't do anything if the</span><br style="font-family:arial,sans-serif;font-size:13px"><span style="font-family:arial,sans-serif;font-size:13px">>>> </span><span style="font-family:arial,sans-serif;font-size:13px">underlying library doesn't do it. But in the case of JPEG or JPEG2000, they do</span><br style="font-family:arial,sans-serif;font-size:13px"><span style="font-family:arial,sans-serif;font-size:13px">>>> </span><span style="font-family:arial,sans-serif;font-size:13px">YCbCr -> RGB conversion transparently. CMYK is quite esoteric, but I think</span><br style="font-family:arial,sans-serif;font-size:13px"><span style="font-family:arial,sans-serif;font-size:13px">>>> </span><span style="font-family:arial,sans-serif;font-size:13px">JPEG will translate it to RGB.</span><br></div><div><br></div><div>I don't understand what would direct the output to be RGB.</div><div><br></div><div>I understand nPixelSpace, nLineSpace, and nBandSpace to be purely a matter of how you want the data laid out in the output buffer, but nothing about what data (type, color space) gets written. So by setting nPixelSpace=3 and nBandSpace=1 as you suggest, I understand that you get sequential RGB triplets, but that in itself doesn't direct <span style="font-size:13px;font-family:arial,sans-serif">RasterIO() to output RGB, right? My understanding is that the only thing that controls the output type is eBuffType, but setting it to GDT_Byte doesn't mean "rgb", it just means "byte". So if the input file had HSL, those bytes would be HSL. And if the input file had RGB or HSL using floats, those byte values would be pinned (i.e., destroyed) versions of the floating point values.</span><br></div><div><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:13px">So I don't see where the "transparent" color space conversion comes in.</span></div><div><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><div>Overall, it's still sounding to me like if I want a function to read an arbitrary file (tiff, JPEG200) into an RGB byte buffer, I need to handle quite a bit of logic myself. I have to:<br></div><div><br></div><div>(a) Look at the number of bands and step through the bands one by one and deduce what color space is being used. For instance, I might see that there are four bands and the first band is <em style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)">GCI_RedBand</em><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)"> , but that does not guarantee that the next two bands are green and blue (although they probably are).</span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)"><br></span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)">(b) Allocate a buffer A to read the file in using its existing color space and data type.</span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)"><br></span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)">(c) Allocate a buffer B in RGB for the given number of pixels.</span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)"><br></span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)">(d) For all the incoming color spaces and data types I choose to support (my understanding is that the possibilities are RBG, HSL, CMYK, YCbCr), for each pixel, grab data from the appropriate channels (in whatever order those channels happen to be laid out) and do both a color space conversion and a data type conversion from the pixel in A to the pixel in B.</span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)"><br></span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)">(e) Possibly deal with other things like the file having a color table (not sure if JPEG200 or tiff can have color tables?), which would modify my code for (d).</span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)"><br></span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)">Does that sound correct to you? Do you know of someone who has that code, even if it's not part of GDAL itself?</span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)"><br></span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)">It still seems to me natural that GDAL would provide an overarching function that would do all of this, since there are a lot of cases to consider and everybody wants basically the same thing.</span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)"><br></span></div><div><span style="color:rgb(0,0,0);font-family:'Lucida Grande',Verdana,Geneva,Arial,sans-serif;font-size:12px;background-color:rgb(251,252,253)">I understand the point about people possibly wanting to map values in a non-linear way or whatever, but it seems like that could be handled with a default behavior with the option for a user callback function to customize.</span></div><div><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Oct 17, 2014 at 4:07 PM, Even Rouault <span dir="ltr"><<a href="mailto:even.rouault@spatialys.com" target="_blank">even.rouault@spatialys.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Le samedi 18 octobre 2014 00:31:16, Michael Katz - NOAA Affiliate a écrit :<br>
> (I apologize if this is a repost. I signed up the for the list yesterday<br>
> and it appeared the first attempt to post was rejected, but I don't know<br>
> how to be sure.)<br>
><br>
> I am using GDAL through the C++ api.<br>
><br>
> I want to be able to read an arbitrary raster file (in particular I'm<br>
> interested in (geo)tiff files and jpeg2000 files) into an RGB buffer, where<br>
> each value is a byte.<br>
><br>
> I was hoping to see an API like dataset->GetRasterRectToBuffer() that would<br>
> operate on the image level (not the band level) and would let me specify<br>
> that my buffer was an RGB byte buffer, and the library would do all the<br>
> right conversions, regardless of the data type and number of bands of the<br>
> source file. For instance, the source file could have CMYK bands with float<br>
> values, and it would still extract correctly to my RGB buffer.<br>
><br>
> Looking at: <a href="http://www.gdal.org/gdal_tutorial.html" target="_blank">http://www.gdal.org/gdal_tutorial.html</a><br>
><br>
> I'm told that the main API to use to read data in GDAL is RasterIO().<br>
><br>
> But I'm scared by RasterIO() because it operates on a band. So that means I<br>
> already have to do my own logic to determine the number of bands in the<br>
> source file and map them to bands in my output RBG file. That seems<br>
> complicated in the general case. It seems like handling all the<br>
> possibilities of RGB, BGR, CMYK, HSL, etc. is exactly the kind of thing a<br>
> data abstraction raster library could save you from having to worry about.<br>
> As I say, I was hoping to find an API that operated at the whole image<br>
> level, not the band level, and could do whatever is best to get an RGB<br>
> image from whatever source. Maybe if it's not part of the GDAL library<br>
> still someone has put together some code to handle arbitrary source image<br>
> to RBG image mapping?<br>
<br>
Michael,<br>
<br>
You can also use GDALDataset::RasterIO() (<br>
<a href="http://www.gdal.org/classGDALDataset.html#ae077c53268d2272eebed10b891a05743" target="_blank">http://www.gdal.org/classGDALDataset.html#ae077c53268d2272eebed10b891a05743</a> )<br>
that can take several bands at once, and by setting nPixelSpace=3 and<br>
nBandSpace=1 (assuming you ask GDT_Byte), you can ask it to put in a buffer<br>
where each R sample is followed immediately by the B and the G, and then you<br>
have the R of the next pixel, etc..<br>
<br>
Regarding color space conversions, GDAL generally doesn't do anything if the<br>
underlying library doesn't do it. But in the case of JPEG or JPEG2000, they do<br>
YCbCr -> RGB conversion transparently. CMYK is quite esoteric, but I think<br>
JPEG will translate it to RGB.<br>
<br>
><br>
> A lesser question is that I'm confused about the design of RasterIO()<br>
> itself. I see from its API description that it does a lot of nice<br>
> conversion as needed:<br>
><br>
> This method allows reading a region of a GDALRasterBand<br>
> <<a href="http://www.gdal.org/classGDALRasterBand.html" target="_blank">http://www.gdal.org/classGDALRasterBand.html</a>> into a buffer, or writing<br>
> data from a buffer into a region of a GDALRasterBand<br>
> <<a href="http://www.gdal.org/classGDALRasterBand.html" target="_blank">http://www.gdal.org/classGDALRasterBand.html</a>>. It automatically takes care<br>
> of data type translation if the data type (eBufType) of the buffer is<br>
> different than that of the GDALRasterBand<br>
> <<a href="http://www.gdal.org/classGDALRasterBand.html" target="_blank">http://www.gdal.org/classGDALRasterBand.html</a>>. The method also takes care<br>
> of image decimation / replication if the buffer size (nBufXSize x<br>
> nBufYSize) is different than the size of the region being accessed (nXSize<br>
> x nYSize).<br>
><br>
><br>
> But then reading the intro tutorial<br>
> (<a href="http://www.gdal.org/gdal_tutorial.html" target="_blank">http://www.gdal.org/gdal_tutorial.html</a>) I see:<br>
><br>
> The pData is the memory buffer the data is read into, or written from. It's<br>
> real type must be whatever is passed as eBufType, such as GDT_Float32, or<br>
> GDT_Byte. The RasterIO() call will take care of converting between the<br>
> buffer's data type and the data type of the band. Note that when converting<br>
> floating point data to integer RasterIO() rounds down,<br>
<br>
That might be actually outdated. Recent GDAL versions should round to the<br>
closest integer.<br>
<br>
> and when converting<br>
> source values outside the legal range of the output the nearest legal value<br>
> is used. This implies, for instance, that 16bit data read into a GDT_Byte<br>
> buffer will map all values greater than 255 to 255, *the data is not<br>
> scaled!*<br>
<br>
Yes, that's true.<br>
Several reasons : how do you scale floating point values that go from -infinity<br>
to +infinity to integer ? And even for integer value, it is not uncommon to<br>
have 12 bit data packed in 16bit, but lack of metadata indicating that it is<br>
actually 12bit, so automatic scaling would not be appropriate.<br>
<br>
><br>
><br>
> Not scaling seems really strange to me, and seems to make RasterIO() much<br>
> less useful. It seems like if I want to get byte values out, I'll need to<br>
> have code that checks the source data type, then allocates a buffer of that<br>
> GDALDataType's size, then does the read, then goes through and<br>
> copies-and-scales each value into my destination RGB buffer, with a<br>
> different case for handling each GDALDataType. I'm just wondering, since<br>
> RasterIO() "automatically takes care of data type translation", why it<br>
> would pin (i.e., destroy) all the data, instead of scaling it. Are 16 bit<br>
> values pinned to byte values (as in the example the tutorial cites) useful<br>
> to anyone?<br>
<br>
Likely not, but at least the behaviour is documented ;-) So yes it is assumed<br>
that people will handle themselves more clever conversions than the one<br>
documented. For example, there are situations where you use non linear scaling<br>
to convert 12bit/16bit to 8bit for better visual rendering.<br>
<br>
Best regards,<br>
<br>
Even<br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
Spatialys - Geospatial professional services<br>
<a href="http://www.spatialys.com" target="_blank">http://www.spatialys.com</a><br>
</font></span></blockquote></div><br></div></div>