2

I want to transform a geojson in a .png image. Do you have any lib/tool/tip to accomplish this task in Java? I googled a lot but no luck.

Francesco
  • 271
  • 2
  • 10

2 Answers2

6

If you chose GeoTools it is a fairly simple process, fetch your geojson from somewhere:

URL states = new URL("http://geojson.xyz/naturalearth-3.3.0/ne_110m_admin_1_states_provinces.geojson");
FeatureJSON featureJSON = new FeatureJSON();
FeatureCollection features = featureJSON.readFeatureCollection(states.openStream());

Then add them to a map with a style:

MapContent mapContent = new MapContent();
mapContent.setTitle("Quickstart");
Style style = SLD.createSimpleStyle(features.getSchema());
Layer layer = new FeatureLayer(features, style);
mapContent.addLayer(layer);

Finally create an image and render the map:

    File outputFile = new File("states.png");
    ImageOutputStream outputImageFile = null;
    FileOutputStream fileOutputStream = null;
    try {
      fileOutputStream = new FileOutputStream(outputFile);
      outputImageFile = ImageIO.createImageOutputStream(fileOutputStream);
      int w = 1000;
      ReferencedEnvelope bounds = features.getBounds();
      int h = (int) (w * (bounds.getHeight() / bounds.getWidth()));
      BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2d = bufferedImage.createGraphics();

      mapContent.getViewport().setMatchingAspectRatio(true);

      mapContent.getViewport().setScreenArea(new Rectangle(Math.round(w), Math.round(h)));
      mapContent.getViewport().setBounds(bounds);

      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

      Rectangle outputArea = new Rectangle(w, h);

      GTRenderer renderer = new StreamingRenderer();
      LabelCacheImpl labelCache = new LabelCacheImpl();
      Map<Object, Object> hints = renderer.getRendererHints();
      if (hints == null) {
        hints = new HashMap<>();
      }
      hints.put(StreamingRenderer.LABEL_CACHE_KEY, labelCache);
      renderer.setRendererHints(hints);
      renderer.setMapContent(mapContent);
      renderer.paint(g2d, outputArea, bounds);
      ImageIO.write(bufferedImage, "png", outputImageFile);
    } catch (IOException ex) {
      ex.printStackTrace();
    } finally {
      try {
        if (outputImageFile != null) {
          outputImageFile.flush();
          outputImageFile.close();
          fileOutputStream.flush();
          fileOutputStream.close();
        }
      } catch (IOException e) {// don't care now
      }
    }
  }
Ian Turton
  • 81,417
  • 6
  • 84
  • 185
  • Hi, thanks for your solution. It works pretty well! How would you define the scale of the geojson file please? – hzitoun May 13 '20 at 15:30
  • 1
    GeoJSON is a vector format - it doesn't have a scale. To scale the map you can change the w variable which is the width of the map. – Ian Turton May 13 '20 at 16:25
  • could you please tell me if there is a way to get the GPS coordinates of a pixel in the outputted image? I want to georeference a sub-image in the big image and get the GPS coordinates. Many thanks in advance. – hzitoun Apr 07 '21 at 08:43
  • any help please? I just want to not loose the GPS coordinates when I generate the image. Is there a way to get a list of matches (x, y) in image <=> (lat, long) in geojson? – hzitoun Jun 03 '21 at 17:27
4

I read points from a shapefile and burn in a png, also with a color classification. The recipe is in python, you need in java but the structure is the same, only must to learn the image java api:

https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html

http://gdal.org/java/

import sys
from osgeo import gdal, ogr
from PIL import Image, ImageDraw

# Filename of input OGR file
vector_fn = 'points.shp'

# Open the data source and read in the extent
datasource = ogr.Open(vector_fn)

if datasource is None:
  print ('Could not open file')
  sys.exit(1)

vector_layer = datasource.GetLayer()


mapXmin, mapXmax, mapYmin, mapYmax = vector_layer.GetExtent()
# http://gdal.org/python/osgeo.ogr.Layer-class.html#GetExtent

print ("mapXmin:",mapXmin)
print ("mapXmax:",mapXmax)
print ("mapYmin:",mapYmin)
print ("mapYmax:",mapYmax)

print(mapXmin,mapYmin,mapXmax,mapYmax)

print ("W:",mapXmax-mapXmin)
print ("H:",mapYmax-mapYmin)

# Define pixel_size 
pixel_size = 0.5 # meters are one pixel
# Create the target data source
target_Width = int(abs(mapXmax - mapXmin) / pixel_size)
target_Height = int(abs(mapYmax - mapYmin) / pixel_size)


print ("target_Width:",target_Width)
print ("target_Height:",target_Height)


image = Image.new('RGBA', (target_Width, target_Height))
draw = ImageDraw.Draw(image)
r=6 #radio
# Loop through the features in the layer
feature = vector_layer.GetNextFeature()
while feature:

  # get the x,y coordinates for the point
  geom = feature.GetGeometryRef()

  xx = geom.GetX();yy = geom.GetY()
  x= int((xx-mapXmin) / pixel_size)
  y= int((mapYmax-yy) / pixel_size)

  value = feature.GetFieldAsDouble('valuation') 
  color = (18,173,42) #dark green
  if(value < 2500): color = (255,0,0) #red
  elif(value < 3000): color = (255,255,0) #yellow


  draw.ellipse((x-r, y-r, x+r, y+r), fill = color, outline =None)
  #draw.point((x, y), 'red')

  # destroy the feature and get a new one
  feature.Destroy()
  feature = vector_layer.GetNextFeature()

# close the data source and text file
datasource.Destroy()

image = image.resize((int(target_Width*0.5), int(target_Height*0.5)), Image.ANTIALIAS)
image.save('circles.png')
Brian Burns
  • 768
  • 5
  • 13
user2232395
  • 262
  • 1
  • 2