Example #1
0
File: twms.py Project: AMDmi3/twms
def twms_main(data):
    """
    Do main TWMS work. 
    data - dictionary of params. 
    returns (error_code, content_type, resp)
    """

    start_time = datetime.datetime.now()

    content_type = "text/html"
    resp = ""
    srs = data.get("srs", "EPSG:4326")
    gpx = data.get("gpx", "").split(",")
    if gpx == ['']:
        gpx = []
    wkt = data.get("wkt", "")
    trackblend = float(data.get("trackblend", "0.5"))
    color = data.get("color", data.get("colour", "")).split(",")
    track = False
    tracks = []
    if len(gpx) == 0:
        req_bbox = projections.from4326(
            (27.6518898, 53.8683186, 27.6581944, 53.8720359), srs)
    else:
        for g in gpx:
            local_gpx = config.gpx_cache + "%s.gpx" % g
            if not os.path.exists(config.gpx_cache):
                os.makedirs(config.gpx_cache)
            if not os.path.exists(local_gpx):
                urllib.urlretrieve(
                    "http://www.openstreetmap.org/trace/%s/data" % g,
                    local_gpx)
            if not track:
                track = GPXParser(local_gpx)
                req_bbox = projections.from4326(track.bbox, srs)
            else:
                track = GPXParser(local_gpx)
                req_bbox = bbox.add(req_bbox,
                                    projections.from4326(track.bbox, srs))
            tracks.append(track)

    req_type = data.get("request", "GetMap")
    version = data.get("version", "1.1.1")
    ref = data.get("ref", config.service_url)
    if req_type == "GetCapabilities":
        content_type, resp = capabilities.get(version, ref)
        return (OK, content_type, resp)

    layer = data.get("layers", config.default_layers).split(",")
    if ("layers" in data) and not layer[0]:
        layer = ["transparent"]

    if req_type == "GetCorrections":
        points = data.get("points", data.get("POINTS", "")).split("=")
        resp = ""
        points = [a.split(",") for a in points]
        points = [(float(a[0]), float(a[1])) for a in points]

        req.content_type = "text/plain"
        for lay in layer:
            for point in points:
                resp += "%s,%s;" % tuple(
                    correctify.rectify(config.layers[lay], point))
            resp += "\n"
        return (OK, content_type, resp)

    force = data.get("force", "")
    if force != "":
        force = force.split(",")
    force = tuple(force)

    filt = data.get("filt", "")
    if filt != "":
        filt = filt.split(",")
    filt = tuple(filt)

    if layer == [""]:
        content_type = "text/html"
        resp = overview.html(ref)
        return (OK, content_type, resp)

    format = data.get("format", config.default_format).lower()
    format = formats.get("image/" + format, format)
    format = formats.get(format, format)
    if format not in formats.values():
        return (ERROR, content_type, "Invalid format")
    content_type = mimetypes[format]

    width = 0
    height = 0
    resp_cache_path, resp_ext = "", ""
    if req_type == "GetTile":
        width = 256
        height = 256
        height = int(data.get("height", height))
        width = int(data.get("width", width))
        srs = data.get("srs", "EPSG:3857")
        x = int(data.get("x", 0))
        y = int(data.get("y", 0))
        z = int(data.get("z", 1)) + 1
        if "cache_tile_responses" in dir(config) and not wkt and (len(gpx)
                                                                  == 0):
            if (srs, tuple(layer), filt, width, height, force,
                    format) in config.cache_tile_responses:

                resp_cache_path, resp_ext = config.cache_tile_responses[(
                    srs, tuple(layer), filt, width, height, force, format)]
                resp_cache_path = resp_cache_path + "/%s/%s/%s.%s" % (
                    z - 1, x, y, resp_ext)
                if os.path.exists(resp_cache_path):
                    return (OK, content_type, open(resp_cache_path,
                                                   "r").read())
        if len(layer) == 1:
            if layer[0] in config.layers:
                if config.layers[layer[0]][
                        "proj"] == srs and width is 256 and height is 256 and not filt and not force and not correctify.has_corrections(
                            config.layers[layer[0]]):
                    local = config.tiles_cache + config.layers[
                        layer[0]]["prefix"] + "/z%s/%s/x%s/%s/y%s." % (
                            z, x / 1024, x, y / 1024, y)
                    ext = config.layers[layer]["ext"]
                    adds = ["", "ups."]
                    for add in adds:
                        if os.path.exists(local + add + ext):
                            tile_file = open(local + add + ext, "r")
                            resp = tile_file.read()
                            return (OK, content_type, resp)
        req_bbox = projections.from4326(projections.bbox_by_tile(z, x, y, srs),
                                        srs)

    if data.get("bbox", None):
        req_bbox = tuple(map(float, data.get("bbox", req_bbox).split(",")))

    req_bbox = projections.to4326(req_bbox, srs)

    req_bbox, flip_h = bbox.normalize(req_bbox)
    box = req_bbox
    #print(req_bbox, file=sys.stderr)
    #sys.stderr.flush()

    height = int(data.get("height", height))
    width = int(data.get("width", width))
    width = min(width, config.max_width)
    height = min(height, config.max_height)
    if (width == 0) and (height == 0):
        width = 350

# layer = layer.split(",")

    imgs = 1.
    ll = layer.pop(0)
    if ll[-2:] == "!c":
        ll = ll[:-2]
        if wkt:
            wkt = "," + wkt
        wkt = correctify.corr_wkt(config.layers[ll]) + wkt
        srs = config.layers[ll]["proj"]
    try:
        result_img = getimg(box, srs, (height, width), config.layers[ll],
                            start_time, force)
    except KeyError:
        result_img = Image.new("RGBA", (width, height))

    #width, height =  result_img.size
    for ll in layer:
        if ll[-2:] == "!c":
            ll = ll[:-2]
            if wkt:
                wkt = "," + wkt
            wkt = correctify.corr_wkt(config.layers[ll]) + wkt
            srs = config.layers[ll]["proj"]

        im2 = getimg(box, srs, (height, width), config.layers[ll], start_time,
                     force)

        if "empty_color" in config.layers[ll]:
            ec = ImageColor.getcolor(config.layers[ll]["empty_color"], "RGBA")
            sec = set(ec)
            if "empty_color_delta" in config.layers[ll]:
                delta = config.layers[ll]["empty_color_delta"]
                for tr in range(-delta, delta):
                    for tg in range(-delta, delta):
                        for tb in range(-delta, delta):
                            if (ec[0] + tr) >= 0 and (ec[0] + tr) < 256 and (
                                    ec[1] + tr
                            ) >= 0 and (ec[1] + tr) < 256 and (
                                    ec[2] + tr) >= 0 and (ec[2] + tr) < 256:
                                sec.add((ec[0] + tr, ec[1] + tg, ec[2] + tb,
                                         ec[3]))
            i2l = im2.load()
            for x in range(0, im2.size[0]):
                for y in range(0, im2.size[1]):
                    t = i2l[x, y]
                    if t in sec:
                        i2l[x, y] = (t[0], t[1], t[2], 0)
        if not im2.size == result_img.size:
            im2 = im2.resize(result_img.size, Image.ANTIALIAS)
        im2 = Image.composite(im2, result_img,
                              im2.split()[3])  # imgs/(imgs+1.))

        if "noblend" in force:
            result_img = im2
        else:
            result_img = Image.blend(im2, result_img, 0.5)
        imgs += 1.

    ##Applying filters
    result_img = filter.raster(result_img, filt, req_bbox, srs)

    #print(wkt, file=sys.stderr)
    #sys.stderr.flush()
    if wkt:
        result_img = drawing.wkt(wkt, result_img, req_bbox, srs,
                                 color if len(color) > 0 else None, trackblend)
    if len(gpx) > 0:
        last_color = None
        c = iter(color)
        for track in tracks:
            try:
                last_color = c.next()
            except StopIteration:
                pass
            result_img = drawing.gpx(track, result_img, req_bbox, srs,
                                     last_color, trackblend)

    if flip_h:
        result_img = ImageOps.flip(result_img)
    image_content = BytesIO()

    if format == "JPEG":
        try:
            result_img.save(image_content,
                            format,
                            quality=config.output_quality,
                            progressive=config.output_progressive)
        except IOError:
            result_img.save(image_content,
                            format,
                            quality=config.output_quality)
    elif format == "PNG":
        result_img.save(image_content,
                        format,
                        progressive=config.output_progressive,
                        optimize=config.output_optimize)
    elif format == "GIF":
        result_img.save(image_content,
                        format,
                        quality=config.output_quality,
                        progressive=config.output_progressive)
    else:  ## workaround for GIF
        result_img = result_img.convert("RGB")
        result_img.save(image_content,
                        format,
                        quality=config.output_quality,
                        progressive=config.output_progressive)
    resp = image_content.getvalue()
    if resp_cache_path:
        try:
            "trying to create local cache directory, if it doesn't exist"
            os.makedirs("/".join(resp_cache_path.split("/")[:-1]))
        except OSError:
            pass
        try:
            a = open(resp_cache_path, "w")
            a.write(resp)
            a.close()
        except (OSError, IOError):
            print("error saving response answer to file %s." %
                  (resp_cache_path),
                  file=sys.stderr)
            sys.stderr.flush()

    return (OK, content_type, resp)
Example #2
0
def twms_main(data):
    """
    Do main TWMS work. 
    data - dictionary of params. 
    returns (error_code, content_type, resp)
    """

    start_time = datetime.datetime.now()

    content_type = "text/html"
    resp = ""
    srs = data.get("srs", "EPSG:4326")
    gpx = data.get("gpx","").split(",")
    wkt = data.get("wkt","")
    trackblend = float(data.get("trackblend","0.5"))
    color = data.get("color",data.get("colour","")).split(",")
    track = False
    tracks = []
    if len(gpx) == 0:
      req_bbox = projections.from4326((27.6518898,53.8683186,27.6581944,53.8720359), srs)
    else:
      for g in gpx:
        local_gpx = config.gpx_cache + "%s.gpx" % g
        if not os.path.exists (config.gpx_cache):
          os.makedirs(config.gpx_cache)
        if not os.path.exists (local_gpx):
            urllib.urlretrieve ("http://www.openstreetmap.org/trace/%s/data" % g, local_gpx)
        if not track:
          track = GPXParser(local_gpx)
          req_bbox = projections.from4326(track.bbox, srs)
        else:
          track = GPXParser(local_gpx)
          req_bbox = bbox.add(req_bbox, projections.from4326(track.bbox, srs))
        tracks.append(track)

    req_type = data.get("request","GetMap")
    version = data.get("version","1.1.1")
    ref = data.get("ref",config.service_url)
    if req_type == "GetCapabilities":
     content_type, resp = capabilities.get(version, ref)
     return (OK, content_type, resp)

    layer = data.get("layers",config.default_layers).split(",")
    if ("layers" in data) and not layer[0]:
      layer = ["transparent"]

    if req_type == "GetCorrections":
       points = data.get("points",data.get("POINTS", "")).split("=")
       resp = ""
       points = [a.split(",") for a in points]
       points = [(float(a[0]), float(a[1])) for a in points]

       req.content_type = "text/plain"
       for lay in layer:
         for point in points:
           resp += "%s,%s;"% tuple(correctify.rectify(config.layers[lay], point))
         resp += "\n"
       return (OK, content_type, resp)


    force = tuple(data.get("force","").split(","))
    filt  = tuple(data.get("filter","").split(","))
    if layer == [""] :
      content_type = "text/html"
      resp = overview.html(ref)
      return (OK, content_type, resp)

    format = data.get("format", config.default_format).lower()
    format = formats.get("image/" + format, format)
    format = formats.get(format, format)
    if format not in formats.values():
       return (ERROR, content_type, "Invalid format")
    content_type = mimetypes[format]

    width=0
    height=0
    resp_cache_path, resp_ext = "",""
    if req_type == "GetTile":
      width=256
      height=256
      height = int(data.get("height",height))
      width = int(data.get("width",width))
      srs = data.get("srs", "EPSG:3857")
      x = int(data.get("x",0))
      y = int(data.get("y",0))
      z = int(data.get("z",1)) + 1
      if "cache_tile_responses" in dir(config) and not wkt and (len(gpx) == 0):
        if (srs, tuple(layer), filt, width, height, force, format) in config.cache_tile_responses:

          resp_cache_path, resp_ext = config.cache_tile_responses[(srs, tuple(layer), filt, width, height, force, format)]
          resp_cache_path = resp_cache_path+"/%s/%s/%s.%s"%(z-1,x,y,resp_ext)
          if os.path.exists(resp_cache_path):
            return (OK, content_type, open(resp_cache_path, "r").read())
      if len(layer) == 1:
       if layer[0] in config.layers:
        if config.layers[layer[0]]["proj"] == srs and width is 256 and height is 256 and not filt and not force and not correctify.has_corrections(layer[0]):
          local = config.tiles_cache + config.layers[layer[0]]["prefix"] + "/z%s/%s/x%s/%s/y%s."%(z, x/1024, x, y/1024,y)
          ext = config.layers[layer]["ext"]
          adds = ["","ups."]
          for add in adds:
           if os.path.exists(local+add+ext):
             tile_file = open(local+add+ext, "r")
             resp = tile_file.read()
             return (OK, content_type, resp)
      req_bbox = projections.from4326(projections.bbox_by_tile(z,x,y,srs),srs)

    if data.get("bbox",None):
      req_bbox = tuple(map(float,data.get("bbox",req_bbox).split(",")))

    req_bbox = projections.to4326(req_bbox, srs)

    req_bbox, flip_h = bbox.normalize(req_bbox)
    box = req_bbox
    #print >> sys.stderr, req_bbox
    #sys.stderr.flush()

    height = int(data.get("height",height))
    width = int(data.get("width",width))
    width = min(width, config.max_width)
    height = min(height, config.max_height)
    if (width == 0) and (height == 0):
      width = 350


   # layer = layer.split(",")

    imgs = 1.
    ll = layer.pop(0)
    if ll[-2:] == "!c":
      ll = ll[:-2]
      if wkt:
        wkt = ","+wkt
      wkt = correctify.corr_wkt(config.layers[ll]) + wkt
      srs = config.layers[ll]["proj"]
    try:
      result_img = getimg(box,srs, (height, width), config.layers[ll], start_time, force)
    except KeyError:
      result_img = Image.new("RGBA", (width,height))


    #width, height =  result_img.size
    for ll in layer:
     if ll[-2:] == "!c":
       ll = ll[:-2]
       if wkt:
         wkt = ","+wkt
       wkt = correctify.corr_wkt(config.layers[ll]) + wkt
       srs = config.layers[ll]["proj"]

     im2 = getimg(box, srs,(height, width), config.layers[ll],  start_time, force)

     if "empty_color" in config.layers[ll]:
      ec = ImageColor.getcolor(config.layers[ll]["empty_color"], "RGBA")
      sec = set(ec)
      if "empty_color_delta" in config.layers[ll]:
        delta = config.layers[ll]["empty_color_delta"]
        for tr in range(-delta, delta):
          for tg in range(-delta, delta):
            for tb in range(-delta, delta):
              if (ec[0]+tr) >= 0  and (ec[0]+tr) < 256 and (ec[1]+tr) >= 0  and (ec[1]+tr) < 256 and(ec[2]+tr) >= 0  and (ec[2]+tr) < 256:
                sec.add((ec[0]+tr,ec[1]+tg,ec[2]+tb,ec[3]))
      i2l = im2.load()
      for x in range(0,im2.size[0]):
        for y in range(0,im2.size[1]):
          t = i2l[x,y]
          if t in sec:
            i2l[x,y] = (t[0],t[1],t[2],0)
     if not im2.size == result_img.size:
         im2 = im2.resize(result_img.size, Image.ANTIALIAS)
     im2 = Image.composite(im2,result_img, im2.split()[3]) # imgs/(imgs+1.))

     if "noblend" in force:
      result_img = im2
     else:
      result_img = Image.blend(im2, result_img, 0.5)
     imgs += 1.

    ##Applying filters
    result_img = filter.raster(result_img, filt, req_bbox, srs)

    #print >> sys.stderr, wkt
    #sys.stderr.flush()
    if wkt:
      result_img = drawing.wkt(wkt, result_img, req_bbox, srs, color if len(color) > 0 else None, trackblend)
    if len(gpx) > 0:
      last_color = None
      c = iter(color)
      for track in tracks:
        try:
          last_color = c.next();
        except StopIteration:
          pass
        result_img = drawing.gpx(track, result_img, req_bbox, srs, last_color, trackblend)

    if flip_h:
      result_img = ImageOps.flip(result_img)
    image_content = StringIO.StringIO()

    if format == "JPEG":
       try:
        result_img.save(image_content, format, quality=config.output_quality, progressive=config.output_progressive)
       except IOError:
        result_img.save(image_content, format, quality=config.output_quality)
    elif format == "PNG":
       result_img.save(image_content, format, progressive=config.output_progressive, optimize =config.output_optimize)
    elif format == "GIF":
       result_img.save(image_content, format, quality=config.output_quality, progressive=config.output_progressive)
    else:       ## workaround for GIF
       result_img = result_img.convert("RGB")
       result_img.save(image_content, format, quality=config.output_quality, progressive=config.output_progressive)
    resp = image_content.getvalue()
    if resp_cache_path:
      try:
        "trying to create local cache directory, if it doesn't exist"
        os.makedirs("/".join(resp_cache_path.split("/")[:-1]))
      except OSError:
         pass
      try:
        a = open(resp_cache_path, "w")
        a.write(resp)
        a.close()
      except (OSError, IOError):
        print >> sys.stderr, "error saving response answer to file %s." % (resp_cache_path)
        sys.stderr.flush()

    return (OK, content_type, resp)
Example #3
0
File: twms.py Project: AMDmi3/twms
def getimg(bbox, request_proj, size, layer, start_time, force):
    orig_bbox = bbox
    ## Making 4-corner maximal bbox
    bbox_p = projections.from4326(bbox, request_proj)
    bbox_p = projections.to4326((bbox_p[2], bbox_p[1], bbox_p[0], bbox_p[3]),
                                request_proj)

    bbox_4 = ((bbox_p[2], bbox_p[3]), (bbox[0], bbox[1]),
              (bbox_p[0], bbox_p[1]), (bbox[2], bbox[3]))
    if "nocorrect" not in force:
        bb4 = []
        for point in bbox_4:
            bb4.append(correctify.rectify(layer, point))
        bbox_4 = bb4
    bbox = bbox_utils.expand_to_point(bbox, bbox_4)
    #print(bbox)
    #print(orig_bbox)

    global cached_objs
    H, W = size

    max_zoom = layer.get("max_zoom", config.default_max_zoom)
    min_zoom = layer.get("min_zoom", 1)

    zoom = bbox_utils.zoom_for_bbox(bbox, size, layer, min_zoom, max_zoom,
                                    (config.max_height, config.max_width))
    lo1, la1, lo2, la2 = bbox
    from_tile_x, from_tile_y, to_tile_x, to_tile_y = projections.tile_by_bbox(
        bbox, zoom, layer["proj"])
    cut_from_x = int(256 * (from_tile_x - int(from_tile_x)))
    cut_from_y = int(256 * (from_tile_y - int(from_tile_y)))
    cut_to_x = int(256 * (to_tile_x - int(to_tile_x)))
    cut_to_y = int(256 * (to_tile_y - int(to_tile_y)))

    from_tile_x, from_tile_y = int(from_tile_x), int(from_tile_y)
    to_tile_x, to_tile_y = int(to_tile_x), int(to_tile_y)
    bbox_im = (cut_from_x, cut_to_y,
               256 * (to_tile_x - from_tile_x) + cut_to_x,
               256 * (from_tile_y - to_tile_y) + cut_from_y)
    x = 256 * (to_tile_x - from_tile_x + 1)
    y = 256 * (from_tile_y - to_tile_y + 1)
    #print(x, y, file=sys.stderr)
    #sys.stderr.flush()
    out = Image.new("RGBA", (x, y))
    for x in range(from_tile_x, to_tile_x + 1):
        for y in range(to_tile_y, from_tile_y + 1):
            got_image = False
            im1 = tile_image(layer, zoom, x, y, start_time, real=True)
            if im1:
                if "prefix" in layer:
                    if (layer["prefix"], zoom, x, y) not in cached_objs:
                        if im1.is_ok:
                            cached_objs[(layer["prefix"], zoom, x, y)] = im1
                            cached_hist_list.append(
                                (layer["prefix"], zoom, x, y))
                            #print((layer["prefix"], zoom, x, y), cached_objs[(layer["prefix"], zoom, x, y)], file=sys.stderr)
                            #sys.stderr.flush()
                    if len(cached_objs) >= config.max_ram_cached_tiles:
                        del cached_objs[cached_hist_list.pop(0)]
                        #print("Removed tile from cache", file=sys.stderr)
                        #sys.stderr.flush()
            else:
                ec = ImageColor.getcolor(
                    layer.get("empty_color", config.default_background),
                    "RGBA")
                #ec = (ec[0],ec[1],ec[2],0)
                im1 = Image.new("RGBA", (256, 256), ec)

            out.paste(im1, (
                (x - from_tile_x) * 256,
                (-to_tile_y + y) * 256,
            ))
    if "filter" in layer:
        out = filter.raster(out, layer["filter"], orig_bbox, request_proj)

    ## TODO: Here's a room for improvement. we could drop this crop in case user doesn't need it.
    out = out.crop(bbox_im)
    if "noresize" not in force:
        if (H == W) and (H == 0):
            W, H = out.size
        if H == 0:
            H = out.size[1] * W // out.size[0]
        if W == 0:
            W = out.size[0] * H // out.size[1]
    #bbox = orig_bbox
    quad = []
    trans_needed = False
    for point in bbox_4:
        x = (point[0] - bbox[0]) / (bbox[2] - bbox[0]) * (out.size[0])
        y = (1 - (point[1] - bbox[1]) / (bbox[3] - bbox[1])) * (out.size[1])
        x = int(round(x))
        y = int(round(y))
        if (x is not 0 and x is not out.size[0]) or (y is not 0
                                                     and y is not out.size[1]):
            trans_needed = True
        quad.append(x)
        quad.append(y)

    if trans_needed:
        quad = tuple(quad)
        out = out.transform((W, H), Image.QUAD, quad, Image.BICUBIC)
    elif (W != out.size[0]) or (H != out.size[1]):
        "just resize"
        out = out.resize((W, H), Image.ANTIALIAS)

# out = reproject(out, bbox, layer["proj"], request_proj)
    return out
Example #4
0
def getimg (bbox, request_proj, size, layer, start_time, force):
   orig_bbox = bbox
   ## Making 4-corner maximal bbox
   bbox_p = projections.from4326(bbox, request_proj)
   bbox_p = projections.to4326((bbox_p[2],bbox_p[1],bbox_p[0],bbox_p[3]), request_proj)
   
   bbox_4 = ( (bbox_p[2],bbox_p[3]),(bbox[0], bbox[1]),(bbox_p[0],bbox_p[1]),(bbox[2],bbox[3]) )
   if "nocorrect" not in force:
     bb4 = []
     for point in bbox_4:
       bb4.append(correctify.rectify(layer, point))
     bbox_4 = bb4
   bbox = bbox_utils.expand_to_point(bbox, bbox_4)
   #print bbox
   #print orig_bbox

   
   global cached_objs
   H,W = size
   
   max_zoom = layer.get("max_zoom",config.default_max_zoom)
   min_zoom = layer.get("min_zoom",1)
   
   zoom = bbox_utils.zoom_for_bbox (bbox,size,layer, min_zoom, max_zoom, (config.max_height,config.max_width))
   lo1, la1, lo2, la2 = bbox
   from_tile_x, from_tile_y, to_tile_x, to_tile_y = projections.tile_by_bbox(bbox, zoom, layer["proj"])
   cut_from_x = int(256*(from_tile_x - int(from_tile_x)))
   cut_from_y = int(256*(from_tile_y - int(from_tile_y)))
   cut_to_x = int(256*(to_tile_x - int(to_tile_x)))
   cut_to_y = int(256*(to_tile_y - int(to_tile_y)))

   from_tile_x, from_tile_y = int(from_tile_x), int(from_tile_y)
   to_tile_x, to_tile_y = int(to_tile_x), int(to_tile_y)
   bbox_im = (cut_from_x, cut_to_y, 256*(to_tile_x-from_tile_x)+cut_to_x, 256*(from_tile_y-to_tile_y)+cut_from_y )
   x = 256*(to_tile_x-from_tile_x+1)
   y = 256*(from_tile_y-to_tile_y+1)
   #print >> sys.stderr, x, y
   #sys.stderr.flush()
   out = Image.new("RGBA", (x, y))
   for x in range (from_tile_x, to_tile_x+1):
    for y in range (to_tile_y, from_tile_y+1):
     got_image = False
     im1 = tile_image (layer,zoom,x,y, start_time, real = True)
     if im1:
      if "prefix" in layer:
       if (layer["prefix"], zoom, x, y) not in cached_objs:
         if im1.is_ok:
          cached_objs[(layer["prefix"], zoom, x, y)] = im1
          cached_hist_list.append((layer["prefix"], zoom, x, y))
          #print >> sys.stderr, (layer["prefix"], zoom, x, y), cached_objs[(layer["prefix"], zoom, x, y)]
          #sys.stderr.flush()
       if len(cached_objs) >= config.max_ram_cached_tiles:
          del cached_objs[cached_hist_list.pop(0)]
          #print >> sys.stderr, "Removed tile from cache", 
          #sys.stderr.flush()
     else:
          ec = ImageColor.getcolor(layer.get("empty_color", config.default_background), "RGBA")
          #ec = (ec[0],ec[1],ec[2],0)
          im1 = Image.new("RGBA", (256, 256), ec)


     out.paste(im1,((x - from_tile_x)*256, (-to_tile_y + y )*256,))
   if "filter" in layer:
     out = filter.raster(out, layer["filter"], orig_bbox, request_proj)

   ## TODO: Here's a room for improvement. we could drop this crop in case user doesn't need it.
   out = out.crop(bbox_im)
   if "noresize" not in force:
      if (H == W) and (H == 0):
        W, H = out.size
      if H == 0:
        H = out.size[1]*W/out.size[0]
      if W == 0:
        W = out.size[0]*H/out.size[1]
   #bbox = orig_bbox
   quad = []
   trans_needed = False
   for point in bbox_4:
     x = (point[0]-bbox[0])/(bbox[2]-bbox[0])*(out.size[0])
     y = (1-(point[1]-bbox[1])/(bbox[3]-bbox[1]))*(out.size[1])
     x = int(round(x))
     y = int(round(y))
     if (x is not 0 and x is not out.size[0]) or (y is not 0 and y is not out.size[1]):
       trans_needed = True
     quad.append(x)
     quad.append(y)
   
   if trans_needed:
     quad = tuple(quad)
     out = out.transform((W,H), Image.QUAD, quad, Image.BICUBIC)
   elif (W != out.size[0]) or (H != out.size[1]):
     "just resize"
     out = out.resize((W,H), Image.ANTIALIAS)
  # out = reproject(out, bbox, layer["proj"], request_proj)
   return out