objets/CImage.js

/*
 * MathGraph32 Javascript : Software for animating online dynamic mathematics figures
 * https://www.mathgraph32.org/
 * @Author Yves Biton (yves.biton@sesamath.net)
 * @License: GNU AGPLv3 https://www.gnu.org/licenses/agpl-3.0.html
 */
import NatObj from '../types/NatObj'
import { base64Encode, cens } from '../kernel/kernel'
import StyleEncadrement from '../types/StyleEncadrement'
import CAffLiePt from './CAffLiePt'
import CValeur from 'src/objets/CValeur'

export default CImage

// Version 7.9 : On ajoute une largeur pour l'image.
// Si la largeur est négative, on garde la largeur initiale de l'image
// Si la largeur est positive, deux caS possibles :
// S'il la figure n'a pas de longueur unité, la largeur donne la largeur en pixels.
// Si la figure comporte une longueur unité, la largeur de la figure est donnée en unités de longueur.
/**
 * Classe représentant une image. Elle est chargée sous forme binaire.
 * @constructor
 * @extends CAffLiePt
 * @param {CListeObjets} listeProprietaire  La liste propriétaire.
 * @param {CImplementationProto} impProto  null ou la construction propriétaire.
 * @param {boolean} estElementFinal  true si élément final de construction.
 * @param {Color} couleur  La couleur de l'objet.
 * @param xNom Abscisse d'affichage
 * @param yNom Ordonnée d'affichage
 * @param {number} decX  Décalage horizontal par rapport à xNom
 * @param {number} decY  Décalage vertical par rapport à yNom
 * @param {boolean} masque  true si l'objet est masqué.
 * @param {CPt} pointLie  null ou le point auquel l'image est liée.
 * @param {number} taillePolice  Indice donnant la taille de la police.
 * @param {StyleEncadrement} encadrement
 * @param {boolean} effacementFond  true si on efface le fond avant d'afficher l'image.
 * @param {Color} couleurFond  La couleur de fond éventuelle.
 * @param {number} alignementHorizontal  0 pour alignement gauche, 1 pour centre, 2 pour droite.
 * @param {number} alignementVertical  0 pour alignement vers le haut, 1 pour centré, 2 pour bas.
 * @param {number} natImage  nombre correspondant à la nature de l'image : 0 pour "png",1 pour "jpg" ou 2 pour "gif"
 * @param {string} image  chaîne de caractères en Base64 contenant le code binaire de l'image.
 * @param {CValeurAngle} angText  L'angle du texte par rapport à l'horizontale
 * @param {CValeur} largeur La largeur de l'image en pixels si pas de longueur unité, si négatif la largeur sera celle de l'image initiale
 * @param {boolean} fixed true si l'affichage est punaisé et ne peut pas être capturé à la souris
 */
function CImage (listeProprietaire, impProto, estElementFinal, couleur, xNom, yNom,
  decX, decY, masque, pointLie, taillePolice, encadrement, effacementFond, couleurFond, alignementHorizontal,
  alignementVertical, natImage, image, angText, largeur, fixed = false) {
  if (arguments.length === 1) CAffLiePt.call(this, listeProprietaire)
  else {
    CAffLiePt.call(this, listeProprietaire, impProto, estElementFinal, couleur,
      xNom, yNom, decX, decY, masque, pointLie, taillePolice, encadrement, effacementFond,
      couleurFond, alignementHorizontal, alignementVertical, angText, fixed)
    this.natImage = natImage
    this.image = image
    this.largeur = largeur
  }
}
CImage.prototype = new CAffLiePt()
CImage.prototype.constructor = CImage
CImage.prototype.superClass = 'CAffLiePt'
CImage.prototype.className = 'CImage'

// Version 7.9 : On passe le numéro de version à 3 en ajoutant une largeur
CImage.prototype.numeroVersion = function () {
  // return 2
  return 3
}

CImage.prototype.getClone = function (listeSource, listeCible) {
  const ind1 = listeSource.indexOf(this.pointLie)
  const ind2 = listeSource.indexOf(this.impProto)
  const angTextClone = this.angText.getClone(listeSource, listeCible)
  const largeurClone = this.largeur.getClone(listeSource, listeCible)
  const ptelb = new CImage(listeCible, listeCible.get(ind2, 'CImplementationProto'),
    this.estElementFinal, this.couleur, this.xNom, this.yNom, this.decX, this.decY,
    this.masque, listeCible.get(ind1, 'CPt'), this.taillePolice, this.encadrement,
    this.effacementFond, this.couleurFond, this.alignementHorizontal, this.alignementVertical,
    this.natImage, this.image, angTextClone, largeurClone, this.fixed)
  ptelb.width = this.width
  ptelb.height = this.height
  return ptelb
}
// Ajout version 6.0
CImage.prototype.setReady4MathJax = function () {
}

CImage.prototype.setReady4MathJaxUpdate = function () {
}

CImage.prototype.depDe = function (p) {
  if (this.elementTestePourDependDe === p) return this.dependDeElementTeste
  return this.memDep(CAffLiePt.prototype.depDe.call(this, p) || this.largeur.depDe(p))
}

// La fonction dependDePourCapture doit être redéfinie car sinon quand on demandé une largeur
// de valeur positive et que donc on veut que la largeur de l'image soit définie par rapport à la
// longeuur unité de la figure (s'il y en a une) il faut que si on capture un des deux points
// définissant la longueur unité de la figure cette fonction renvoie true
CImage.prototype.dependDePourCapture = function (p) {
  const dep = this.depDe(p)
  const longUnit = this.listeProprietaire.pointeurLongueurUnite
  if (longUnit !== null && longUnit.depDe(p)) {
    const long = this.largeur.rendValeur()
    if (long > 0) return true
    else return dep
  } else {
    return dep
  }
}

CImage.prototype.dependDePourBoucle = function (p) {
  return CAffLiePt.prototype.dependDePourBoucle.call(this, p) || this.largeur.dependDePourBoucle(p)
}

/**
 *
 * @param {boolean} infoRandom
 * @param {Dimf} dimfen
 */
CImage.prototype.positionne = function (infoRandom, dimfen) {
  CAffLiePt.prototype.positionnePourIm.call(this, infoRandom, dimfen)
  if (!this.existe) return
  this.largeur.positionne(infoRandom, dimfen)
  this.existe = this.largeur.existe
  if (!this.existe) return
  /* Modifié version 6.0
  this.rectAff.x = this.xNom + this.decX;
  this.rectAff.y = this.yNom + this.decY;
   */
  // reset de la position du Rect, que l'on va affiner ci-dessous
  this.rectAff.x = 0
  this.rectAff.y = 0
  let largeur = this.largeur.rendValeur()
  // Si la largeur est strictement positive c'est que la largeur de l'image est donnée en longueurs unités
  // et donc l'image doit être définie après la longueur unité sinon elle n'existe pas
  if (largeur > 0) {
    const longInit = this.listeProprietaire.pointeurLongueurUnite
    if (longInit !== null && (this.index < longInit.index)) {
      this.existe = false
      return
    }
  }
  let hauteur
  const longunit = this.listeProprietaire.pointeurLongueurUnite
  if (largeur === 0 || ((largeur > 0) && (longunit === null))) {
    largeur = this.width
    hauteur = this.height
  } else {
    if (largeur < 0) {
      largeur = Math.abs(largeur)
      hauteur = Math.abs(largeur / this.width * this.height)
    } else {
      const disunit = longunit.rendLongueur() // Longueur en pixels de la longueur unité
      largeur = largeur * disunit
      hauteur = largeur / this.width * this.height
    }
  }
  this.actualWidth = largeur
  this.actualHeight = hauteur

  // Modification version 4.5
  switch (this.alignementHorizontal) {
    case CAffLiePt.alignHorCent :
      this.rectAff.x -= largeur / 2
      break
    case CAffLiePt.alignHorRight :
      this.rectAff.x -= largeur
  }
  switch (this.alignementVertical) {
    case CAffLiePt.alignVerCent :
      this.rectAff.y -= hauteur / 2
      break
    case CAffLiePt.alignVerLow :
      this.rectAff.y -= hauteur
  }
}
CImage.prototype.createg = function () {
  const g = cens('g')
  this.rectAff.width = this.actualWidth + 3
  this.rectAff.height = this.actualHeight + 3
  const image = cens('image', {
    x: this.rectAff.x,
    y: this.rectAff.y,
    width: this.actualWidth,
    height: this.actualHeight,
    'pointer-events': 'none'
  })
  const tab = ['png', 'gif', 'jpg']
  const ext = tab[this.natImage]
  image.setAttributeNS('http://www.w3.org/1999/xlink', 'href', 'data:image/' + ext + ';base64,' + base64Encode(this.image, true))
  image.style.opacity = this.couleur.opacity
  g.appendChild(image)
  if (this.effacementFond || (this.encadrement !== StyleEncadrement.Sans)) this.creeRectangle(g)
  // Ajout version Version 6.0 //////////////////////////////////////////
  this.positionneAngText(g)
  /// //////////////////////////////////////////////////////////////////////
  // Ligne suivante ajoutée version 6.5.2
  g.setAttribute('pointer-events', this.pointerevents)
  return g
}
CImage.prototype.update = function () {
  if (this.g !== null) {
    this.rectAff.width = this.actualWidth + 3
    this.rectAff.height = this.actualHeight + 3
    const img = this.g.childNodes[this.g.childNodes.length - 1]
    // g.removeAttribute("x");
    // g.removeAttribute("y");
    img.setAttribute('x', this.rectAff.x)
    img.setAttribute('y', this.rectAff.y)
    img.setAttribute('width', this.actualWidth)
    img.setAttribute('height', this.actualHeight)
    if (this.effacementFond || (this.encadrement !== StyleEncadrement.Sans)) this.remplaceRectangle(this.g, this.couleurFond)
    this.positionneAngText(this.g)
  }
}
CImage.prototype.ajouteAntecedents = function (liste) {
  if (this.pointLie !== null) liste.add(this.pointLie)
}
CImage.prototype.getNature = function () {
  return NatObj.NImage
}
CImage.prototype.rendChaineAffichage = function () {
  return ''
}
CImage.prototype.chaineDesignation = function () {
  return 'desImage'
}

// Rajout version 6.0 pour pouvoir créer un lieu d'objet d'un image
CImage.prototype.setClone = function (ptel) {
  CAffLiePt.prototype.setClone.call(this, ptel)
  this.largeur.valeur = ptel.largeur.valeur
  this.actualWidth = ptel.actualWidth
  this.actualHeight = ptel.actualHeight
  this.rectAff.setClone(ptel.rectAff)
}

CImage.prototype.read = function (inps, list) {
  CAffLiePt.prototype.read.call(this, inps, list)
  this.natImage = inps.readByte()
  this.width = inps.readInt()
  this.height = inps.readInt()
  this.image = inps.readBufferedImage()
  if (this.nVersion > 2) {
    this.largeur = new CValeur()
    this.largeur.read(inps, list)
  } else {
    this.largeur = new CValeur(list, 0) // 0 pour garder par défaut les dimensions en pixels de l'iamage
  }
}
CImage.prototype.write = function (oups, list) {
  CAffLiePt.prototype.write.call(this, oups, list)
  oups.writeByte(this.natImage)
  oups.writeInt(this.width)
  oups.writeInt(this.height)
  oups.writeBufferedImage(this.image, this.natImage)
  this.largeur.write(oups, list)
}