private void LoadTileDataSync(PositionKey key, ICachedTile tile) { var red = RawDataPool.Capture(); var green = RawDataPool.Capture(); var blue = RawDataPool.Capture(); try { if (key == null || tile == null) { return; } var name = key.ToString(); var res = _tileStore.Exists(name); if (res.IsFailure) { tile.SetState(TileState.Empty); return; } var version = res.ResultData?.CurrentVersion ?? 1; var img = _tileStore.Read(name, "img", version); if (img.IsFailure || img.ResultData == null) { tile.SetState(TileState.Empty); return; } var fileData = InterleavedFile.ReadFromStream(img.ResultData); if (fileData != null) { WaveletCompress.Decompress(fileData, red, green, blue, 1); } tile.EnsureDataReady(); var packed = tile.GetTileData() ?? throw new Exception("Byte pool allocation failed"); var end = TileImageSize * TileImageSize; for (int i = 0; i < end; i++) { packed[4 * i + 0] = blue[i]; packed[4 * i + 1] = green[i]; packed[4 * i + 2] = red[i]; if (blue[i] >= 254 && green[i] >= 254 && red[i] >= 254) { packed[4 * i + 3] = 0; } else { packed[4 * i + 3] = 255; } } tile.SetState(TileState.Ready); } catch (Exception ex) { Logging.WriteLogMessage("Failed to load tile data\r\n" + ex); tile?.MarkCorrupted(); } finally { RawDataPool.Release(red); RawDataPool.Release(green); RawDataPool.Release(blue); } }
/// <summary> /// Write an image onto a tile, with transparency. /// Returns true if any pixels were changed. /// `tileArea` is in tile space. `imageArea` is in image space. /// </summary> /// <remarks>The scaling here is only intended for small variations (between 0.6x and 1.4x). The /// Source image should be scaled if you are outside of this range</remarks> private bool AlphaMapImageToTileScaled(RawImageInterleaved_UInt8 img, ICachedTile tile, Quad imageArea, Quad tileArea) { // This needs to be improved var dst = tile?.GetTileData(); var src = img?.Data; if (src == null || dst == null || imageArea == null || tileArea == null) { return(false); } if (img.Width < 1 || img.Height < 1) { return(false); } bool changed = false; // start and end limits on tile int x0 = (int)Math.Max(tileArea.X, 0); int x1 = (int)Math.Min(tileArea.X + tileArea.Width, TileImageSize); int y0 = (int)Math.Max(tileArea.Y, 0); int y1 = (int)Math.Min(tileArea.Y + tileArea.Height, TileImageSize); int dst_width = x1 - x0; int dst_height = y1 - y0; if (dst_width < 1 || dst_height < 1) { return(false); } double scale_x = imageArea.Width / dst_width; double scale_y = imageArea.Height / dst_height; var imgyo = imageArea.Y; var imgxo = imageArea.X; // AA caches int[] src_aa = new int[(img.Width + 1) * 4]; for (int y = y0; y < y1; y++) { var img_yi = y - y0; // prepare a scaled row here AntiAliasRow(img, img_yi, scale_y, imgyo, src, src_aa); // copy image row for (int x = x0; x < x1; x++) { var img_xi = x - x0; // Measure AA var xoff_f = Range(0.0, (img_xi * scale_x) + imgxo, img.Width); var xoff = (int)xoff_f; double x_frac = xoff_f - xoff; var imul = (int)(255 * x_frac); var mul = 255 - imul; var src_xi = xoff * 4; var src_i = Range(0, src_xi, src_aa.Length - 4); // offset into source raw image var src_i2 = Range(0, src_xi + 4, src_aa.Length - 4); // offset into source raw image var dst_i = y * (TileImageSize * 4) + (x * 4); // offset into tile data if (dst_i < 0) { continue; } if (dst_i >= dst.Length) { continue; } // Threshold alpha if (src_aa[src_i + 3] < 2 && src_aa[src_i2 + 3] < 2) { continue; } // Take source samples and do AA var srcB = ((src_aa[src_i + 0] * mul) + (src_aa[src_i2 + 0] * imul)) >> 8; var srcG = ((src_aa[src_i + 1] * mul) + (src_aa[src_i2 + 1] * imul)) >> 8; var srcR = ((src_aa[src_i + 2] * mul) + (src_aa[src_i2 + 2] * imul)) >> 8; var srcA = ((src_aa[src_i + 3] * mul) + (src_aa[src_i2 + 3] * imul)) >> 8; var newAlpha = srcA / 255.0f; var oldAlpha = 1.0f - newAlpha; // Alpha blend over existing color // This for plain alpha: //dst[dst_i + 0] = Clip((dst[dst_i + 0] * oldAlpha) + (src[src_i + 0] * newAlpha)); //dst[dst_i + 1] = Clip((dst[dst_i + 1] * oldAlpha) + (src[src_i + 1] * newAlpha)); //dst[dst_i + 2] = Clip((dst[dst_i + 2] * oldAlpha) + (src[src_i + 2] * newAlpha)); // This for pre-multiplied alpha dst[dst_i + 0] = Clip((dst[dst_i + 0] * oldAlpha) + srcB); dst[dst_i + 1] = Clip((dst[dst_i + 1] * oldAlpha) + srcG); dst[dst_i + 2] = Clip((dst[dst_i + 2] * oldAlpha) + srcR); dst[dst_i + 3] = 255; // tile alpha is always 100% changed = true; } } return(changed); }