plugin/tif: Minimal geotiff capabilities

This commit is contained in:
Mirek Fidler 2022-05-04 00:03:49 +02:00
parent a7b773ba32
commit b11938a43c
4 changed files with 121 additions and 17 deletions

View file

@ -53,6 +53,16 @@ int Raster::GetPageDisposal(int n)
return 0;
}
Value Raster::GetMetaData(String id)
{
return Value();
}
void Raster::EnumMetaData(Vector<String>& id_list)
{
id_list.Clear();
}
void Raster::Line::Pick(Line&& b)
{
data = b.data;

View file

@ -144,10 +144,13 @@ public:
virtual const RGBA *GetPalette();
virtual const RasterFormat *GetFormat();
virtual Value GetMetaData(String id);
virtual void EnumMetaData(Vector<String>& id_list);
int GetWidth() { return GetSize().cx; }
int GetHeight() { return GetSize().cy; }
Line operator[](int i) { return GetLine(i); }
Image GetImage(int x, int y, int cx, int cy, const Gate<int, int> progress = Null);
Image GetImage(const Gate<int, int> progress = Null);

View file

@ -56,6 +56,9 @@ public:
virtual int GetActivePage() const;
virtual void SeekPage(int n);
virtual Value GetMetaData(String id);
virtual void EnumMetaData(Vector<String>& id_list);
private:
bool Init();
};

View file

@ -583,9 +583,11 @@ struct TIFRaster::Data : public TIFFRGBAImage {
};
Array<Page> pages;
int page_index;
VectorMap<String, Value> attr;
byte *MapDown(int x, int y, int count, bool read);
byte *MapUp(int x, int y, int count, bool read);
byte *MapDown(int x, int y, int count);
byte *MapUp(int x, int y, int count);
void Flush();
void Flush(int y);
@ -634,7 +636,7 @@ static void packTileRGB(TIFRaster::Data *helper, uint32 x, uint32 y, uint32 w, u
const byte *src = (const byte *)helper->buffer.Begin();
// unsigned srow = sizeof(uint32) * w; //, drow = helper->dest.GetUpRowBytes();
for(; h; h--, /*src += srow,*/ /*dest += drow*/ y++) {
for(byte *dest = helper->MapUp(x4, y, w4, false), *end = dest + w4; dest < end; dest += 4, src += 4) {
for(byte *dest = helper->MapUp(x4, y, w4), *end = dest + w4; dest < end; dest += 4, src += 4) {
dest[0] = src[2];
dest[1] = src[1];
dest[2] = src[0];
@ -648,7 +650,7 @@ static void packTileRGB(TIFRaster::Data *helper, uint32 x, uint32 y, uint32 w, u
const byte *src = (const byte *)helper->buffer.Begin();
// unsigned srow = sizeof(uint32) * w; //, drow = helper->dest.GetUpRowBytes();
for(; h; h--, /*src += srow,*/ /*dest += drow*/ y++) {
for(byte *dest = helper->MapUp(x3, y, w3, false), *end = dest + w3; dest < end; dest += 3, src += 4) {
for(byte *dest = helper->MapUp(x3, y, w3), *end = dest + w3; dest < end; dest += 3, src += 4) {
dest[0] = src[2];
dest[1] = src[1];
dest[2] = src[0];
@ -674,7 +676,7 @@ static void putContig1(TIFFRGBAImage *img, tif_uint32 *cp,
const byte *src = pp;
int srow = (fromskew + w - 1) / helper->skewfac + 1;
for(; h; h--, y += drow /*dest += drow*/, src += srow)
BltPack11(helper->MapUp(x8, y, w8, read), src, (byte)(x & 7), w);
BltPack11(helper->MapUp(x8, y, w8), src, (byte)(x & 7), w);
}
static void putContig2(TIFFRGBAImage *img, tif_uint32 *cp,
@ -694,7 +696,7 @@ static void putContig2(TIFFRGBAImage *img, tif_uint32 *cp,
const byte *src = pp;
int srow = (fromskew + w - 1) / helper->skewfac + 1;
for(; h; h--, y += drow /*dest += drow*/, src += srow)
BltPack22(helper->MapUp(x4, y, w4, read), src, (byte)(x & 3), w);
BltPack22(helper->MapUp(x4, y, w4), src, (byte)(x & 3), w);
}
static void putContig4(TIFFRGBAImage *img, tif_uint32 *cp,
@ -715,7 +717,7 @@ static void putContig4(TIFFRGBAImage *img, tif_uint32 *cp,
const byte *src = pp;
int srow = (fromskew + w - 1) / helper->skewfac + 1;
for(; h; h--, y /*dest*/ += drow, src += srow)
BltPack44(helper->MapUp(x2, y, w2, read), src, shift, w);
BltPack44(helper->MapUp(x2, y, w2), src, shift, w);
}
static void putContig8(TIFFRGBAImage *img, tif_uint32 *cp,
@ -732,7 +734,7 @@ static void putContig8(TIFFRGBAImage *img, tif_uint32 *cp,
const byte *src = pp;
int srow = (fromskew + w - 1) / helper->skewfac + 1;
for(; h; h--, y /*dest*/ += drow, src += srow)
memcpy(helper->MapUp(x, y, w, false), src, w);
memcpy(helper->MapUp(x, y, w), src, w);
}
static void putContigRGB(TIFFRGBAImage *img, tif_uint32 *cp, tif_uint32 x, tif_uint32 y, tif_uint32 w, tif_uint32 h,
@ -766,12 +768,12 @@ static void putSeparate(TIFFRGBAImage *img, tif_uint32 *cp,
packTileRGB(helper, x, keep_y ? y : y - h + 1, w, h);
}
byte *TIFRaster::Data::MapUp(int x, int y, int count, bool read)
byte *TIFRaster::Data::MapUp(int x, int y, int count)
{
return MapDown(x, size.cy - 1 - y, count, read);
return MapDown(x, size.cy - 1 - y, count);
}
byte *TIFRaster::Data::MapDown(int x, int y, int count, bool read)
byte *TIFRaster::Data::MapDown(int x, int y, int count)
{
if(!imagebuf.IsEmpty())
return &imagebuf[row_bytes * y] + x;
@ -783,10 +785,8 @@ byte *TIFRaster::Data::MapDown(int x, int y, int count, bool read)
Flush();
row.mapping.Alloc(row_bytes, 0);
cache_size++;
if(read) {
filebuffer.Seek(row_bytes * y);
filebuffer.GetAll(row.mapping, count);
}
filebuffer.Seek(row_bytes * y);
filebuffer.GetAll(row.mapping, count);
}
return row.mapping + x;
}
@ -896,6 +896,84 @@ bool TIFRaster::Data::Create()
page.alpha = true;
break;
}
if(i == 0) {
const word TIFFTAG_GEOPIXELSCALE = 33550,
TIFFTAG_GEOTIEPOINTS = 33922,
TIFFTAG_GEOTRANSMATRIX = 34264,
TIFFTAG_GEOKEYDIRECTORY = 34735,
TIFFTAG_GEODOUBLEPARAMS = 34736,
TIFFTAG_GEOASCIIPARAMS = 34737;
word count = 0;
word *geokeys = nullptr;
bool pixel_is_area = false;
if(TIFFGetField(tiff, TIFFTAG_GEOKEYDIRECTORY, &count, &geokeys) &&
count >= 4 && (count % 4) == 0 && geokeys[0] == 1)
for(int i = 4; i + 3 < count; i += 4) {
const word GTRasterTypeGeoKey = 1025,
RasterPixelIsArea = 1,
GeographicTypeGeoKey = 2048,
ProjectedCSTypeGeoKey = 3072;
word value = geokeys[i + 3];
switch(geokeys[i]) {
case GTRasterTypeGeoKey:
pixel_is_area = value == RasterPixelIsArea;
break;
case GeographicTypeGeoKey:
case ProjectedCSTypeGeoKey:
attr.GetAdd("epsg") = value;
break;
}
}
double geomatrix[6];
geomatrix[0] = 0.0;
geomatrix[1] = 1.0;
geomatrix[2] = 0.0;
geomatrix[3] = 0.0;
geomatrix[4] = 0.0;
geomatrix[5] = 1.0;
double *data;
auto FinishMatrix = [&] {
if(!pixel_is_area) {
geomatrix[0] -= (geomatrix[1] * 0.5 + geomatrix[2] * 0.5);
geomatrix[3] -= (geomatrix[4] * 0.5 + geomatrix[5] * 0.5);
}
ValueArray va;
for(int i = 0; i < 6; i++)
va << geomatrix[i];
attr.GetAdd("geo_matrix") = va;
};
if(TIFFGetField(tiff, TIFFTAG_GEOTRANSMATRIX, &count, &data) && count == 16) {
geomatrix[0] = data[3];
geomatrix[1] = data[0];
geomatrix[2] = data[1];
geomatrix[3] = data[7];
geomatrix[4] = data[4];
geomatrix[5] = data[5];
FinishMatrix();
}
else
if(TIFFGetField(tiff, TIFFTAG_GEOPIXELSCALE, &count, &data) &&
count >= 2 && data[0] && data[1]) {
geomatrix[1] = data[0];
geomatrix[5] = -abs(data[1]);
if(TIFFGetField(tiff, TIFFTAG_GEOTIEPOINTS, &count, &data) && count >= 6) {
geomatrix[0] = data[3] - data[0] * geomatrix[1];
geomatrix[3] = data[4] - data[1] * geomatrix[5];
FinishMatrix();
}
}
}
}
return SeekPage(0);
}
@ -1063,7 +1141,7 @@ Raster::Line TIFRaster::Data::GetLine(int line, Raster *raster)
}
if(!imagebuf.IsEmpty())
return Raster::Line(&imagebuf[row_bytes * line], raster, false);
const byte *data = MapDown(0, line, row_bytes, raster);
const byte *data = MapDown(0, line, row_bytes);
byte *tmp = new byte[row_bytes];
memcpy(tmp, data, row_bytes);
return Raster::Line(tmp, raster, true);
@ -1128,6 +1206,16 @@ void TIFRaster::SeekPage(int n)
data->SeekPage(n);
}
Value TIFRaster::GetMetaData(String id)
{
return data->attr.Get(id, Value());
}
void TIFRaster::EnumMetaData(Vector<String>& id_list)
{
id_list = clone(data->attr.GetKeys());
}
class TIFEncoder::Data {
public:
Data(Stream& stream, RasterFormat& format);