diff --git a/Code/IO/otbJPEG2000ImageIO.cxx b/Code/IO/otbJPEG2000ImageIO.cxx
index d5e169798a55ff5604652a673d11d7c7ceb9dc86..b947d8f72b097e49da8f356516c7fecda385bf9d 100644
--- a/Code/IO/otbJPEG2000ImageIO.cxx
+++ b/Code/IO/otbJPEG2000ImageIO.cxx
@@ -33,6 +33,12 @@ extern "C"
 #include "openjpeg.h"
 }
 
+#include "gdal.h"
+#include "gdaljp2metadata.h"
+#include "cpl_string.h"
+#include "ogr_spatialref.h"
+#include "ogr_srs_api.h"
+
 /**
 Divide an integer by a power of 2 and round upwards
 @return Returns a divided by 2^b
@@ -75,7 +81,8 @@ void info_callback(const char *msg, void *client_data)
 
 namespace otb
 {
-/** Compute offsets needed to read the data from the tile decoded and offsets needed to write into the output buffer */
+/** Compute offsets needed to read the data from the tile decoded and
+ * offsets needed to write into the output buffer */
 void ComputeOffsets(opj_image_t * tile,
                     const itk::ImageIORegion & ioRegion,
                     unsigned int &l_width_src,
@@ -84,7 +91,80 @@ void ComputeOffsets(opj_image_t * tile,
                     unsigned int &l_start_offset_dest,
                     unsigned int &l_start_offset_src);
 
+/************************************************************************/
+/*     JPEG2000 metadata reader based on GDAL functionalities           */
+/************************************************************************/
+class JPEG2000MetadataReader
+{
+public:
+  JPEG2000MetadataReader(const char *filename )
+  {
+  m_MetadataIsRead = false;
+
+  if( m_JP2Metadata.ReadAndParse(filename) )
+    {
+    m_MetadataIsRead = true;
+    }
+
+  };
+
+  ~JPEG2000MetadataReader(){};
+
+  /** Get the geoTransform from file*/
+  std::vector<double> GetGeoTransform(){
+    std::vector<double> geoTransform;
+    for (unsigned int i = 0; i< 6; i++ )
+      geoTransform.push_back(m_JP2Metadata.adfGeoTransform[i]);
+    return geoTransform;
+  };
+
+  /** Check if image in the file have a geoTransform*/
+  bool HaveGeoTransform(){
+    return static_cast<bool>(m_JP2Metadata.bHaveGeoTransform);
+  };
+
+  /** Get the nb of GCP from file*/
+  int GetGCPCount(){
+    return m_JP2Metadata.nGCPCount;
+  };
+
+  /** Get the GCPs from file*/
+  std::vector<GDAL_GCP> GetGCPs(){
+    std::vector<GDAL_GCP> gcps;
+    int nbGCP = m_JP2Metadata.nGCPCount;
+    for (int i = 0; i< nbGCP; i++ )
+      gcps.push_back(m_JP2Metadata.pasGCPList[i]);
+    return gcps;
+  };
+
+  /** Get the projectionRef from file*/
+  const char* GetProjectionRef() {
+    if (m_JP2Metadata.pszProjection)
+      return m_JP2Metadata.pszProjection;
+    else
+      return NULL;
+  };
+
+  /** Get the GML box from file*/
+  char** GetGMLMetadata() {
+    if (m_JP2Metadata.papszGMLMetadata)
+      return m_JP2Metadata.papszGMLMetadata;
+    else
+      return NULL;
+  };
+
+  /** Check if the file has been correctly read*/
+  bool m_MetadataIsRead;
 
+private:
+  /** GDAL structure where store metadata read from JP2 file*/
+  GDALJP2Metadata m_JP2Metadata;
+
+};
+
+/************************************************************************/
+/*            JPEG2000 internal reader based on openjpeg                */
+/************************************************************************/
 class JPEG2000InternalReader
 {
 public:
@@ -391,7 +471,9 @@ int JPEG2000InternalReader::CanRead()
    else return 0;
  }
 
-
+/************************************************************************/
+/*            Class to manage JPEG2000 tile cache system                */
+/************************************************************************/
 class JPEG2000TileCache
 {
 public:
@@ -559,6 +641,9 @@ void JPEG2000TileCache::AddTile(unsigned int tileIndex, opj_image_t * tileData)
   m_Cache.push_back(CachedTileType(tileIndex, tileData));
 }
 
+/************************************************************************/
+/*                     JPEG2000ImageIO                                  */
+/************************************************************************/
 JPEG2000ImageIO::JPEG2000ImageIO()
 {
   // Initialize multi-threader
@@ -993,6 +1078,122 @@ void JPEG2000ImageIO::ReadImageInformation()
                                     MetaDataKey::CacheSizeInBytes,
                                     m_CacheSizeInByte);
 
+  // Now initialize the itk dictionary
+  itk::MetaDataDictionary& dict = this->GetMetaDataDictionary();
+
+  JPEG2000MetadataReader lJP2MetadataReader(m_FileName.c_str());
+
+  if (lJP2MetadataReader.m_MetadataIsRead)
+    {
+    otbMsgDevMacro(<< "JPEG2000 file has metadata available!");
+
+    /* GEOTRANSFORM */
+    if (lJP2MetadataReader.HaveGeoTransform())
+      {
+      otbMsgDevMacro(<< "JPEG2000 file has a geotransform!");
+      std::vector<double> geoTransform = lJP2MetadataReader.GetGeoTransform();
+
+      itk::EncapsulateMetaData<MetaDataKey::VectorType>(dict, MetaDataKey::GeoTransformKey, geoTransform);
+
+      // retrieve origin and spacing from the geo transform ????
+      /*m_Origin[0] = geoTransform[0];
+      m_Origin[1] = geoTransform[3];
+      m_Spacing[0] = geoTransform[1];
+      m_Spacing[1] = geoTransform[5];*/
+      }
+
+    /* GCPs */
+    if (lJP2MetadataReader.GetGCPCount() > 0)
+      {
+      // No GCPprojRef return by GDALJP2metadata
+      std::string gcpProjectionKey = static_cast<std::string>("UNKNOWN");
+      itk::EncapsulateMetaData<std::string>(dict, MetaDataKey::GCPProjectionKey, gcpProjectionKey);
+
+      int nbGCPs = lJP2MetadataReader.GetGCPCount();
+      otbMsgDevMacro(<< "JPEG2000 file has "<< nbGCPs << " GCPs!");
+      itk::EncapsulateMetaData<int>(dict, MetaDataKey::GCPCountKey, nbGCPs);
+
+      std::vector<GDAL_GCP> gcps = lJP2MetadataReader.GetGCPs();
+
+      std::string key;
+      for (int cpt = 0; cpt < nbGCPs; ++cpt)
+        {
+        GDAL_GCP currentGCP = gcps[cpt];
+        OTB_GCP pOtbGCP;
+        pOtbGCP.m_Id = std::string(currentGCP.pszId);
+        pOtbGCP.m_Info = std::string(currentGCP.pszInfo);
+        pOtbGCP.m_GCPRow = currentGCP.dfGCPLine;
+        pOtbGCP.m_GCPCol = currentGCP.dfGCPPixel;
+        pOtbGCP.m_GCPX = currentGCP.dfGCPX;
+        pOtbGCP.m_GCPY = currentGCP.dfGCPY;
+        pOtbGCP.m_GCPZ = currentGCP.dfGCPZ;
+
+        // Complete the key with the GCP number : GCP_i
+        std::ostringstream lStream;
+        lStream << MetaDataKey::GCPParametersKey << cpt;
+        key = lStream.str();
+
+        itk::EncapsulateMetaData<OTB_GCP>(dict, key, pOtbGCP);
+        }
+      }
+
+    /* GMLMetadata*/
+    char** papszGMLMetadata;
+    papszGMLMetadata =  lJP2MetadataReader.GetGMLMetadata();
+    if (CSLCount(papszGMLMetadata) > 0)
+      {
+      otbMsgDevMacro(<< "JPEG2000 file has GMLMetadata!");
+      std::string key;
+
+      for (int cpt = 0; papszGMLMetadata[cpt] != NULL; ++cpt)
+        {
+        std::ostringstream lStream;
+        lStream << MetaDataKey::MetadataKey << cpt;
+        key = lStream.str();
+
+        itk::EncapsulateMetaData<std::string>(dict, key, static_cast<std::string> (papszGMLMetadata[cpt]));
+        }
+      }
+
+
+    /* ProjectionRef*/
+    if (lJP2MetadataReader.GetProjectionRef() && !std::string(lJP2MetadataReader.GetProjectionRef()).empty() )
+      {
+      OGRSpatialReferenceH pSR = OSRNewSpatialReference(NULL);
+
+      const char * pszProjection = NULL;
+      pszProjection =  lJP2MetadataReader.GetProjectionRef();
+
+      if (OSRImportFromWkt(pSR, (char **) (&pszProjection)) == OGRERR_NONE)
+        {
+        char * pszPrettyWkt = NULL;
+        OSRExportToPrettyWkt(pSR, &pszPrettyWkt, FALSE);
+
+        itk::EncapsulateMetaData<std::string> (dict, MetaDataKey::ProjectionRefKey,
+                                               static_cast<std::string>(pszPrettyWkt));
+
+        CPLFree(pszPrettyWkt);
+        }
+      else
+        {
+        itk::EncapsulateMetaData<std::string>(dict, MetaDataKey::ProjectionRefKey,
+                                              static_cast<std::string>(lJP2MetadataReader.GetProjectionRef()));
+        }
+
+      if (pSR != NULL)
+        {
+        OSRRelease(pSR);
+        pSR = NULL;
+        }
+
+      }
+
+    //dict.Print(std::cout);
+    }
+  else
+    {
+    otbMsgDevMacro( << "JPEG2000 file has NO metadata available!");
+    }
 
   // If the internal image was not open we open it.
   // This is usually done when the user sets the ImageIO manually
@@ -1322,12 +1523,6 @@ void ComputeOffsets( opj_image_t * currentTile,
   */
 }
 
-/** Get Info about all resolution in jpeg2000 file */
-bool GetResolutionInfo(std::vector<unsigned int>& res, std::vector<std::string>& desc)
-{
-  return true;
-}
-
 // Not yet implemented
 bool JPEG2000ImageIO::CanWriteFile(const char* /*filename*/)
 {