#include #include #include #include #include class BMP2Gcode { public: BMP2Gcode(); void traitement(char* nom_fichier); void fichier_conf(); private: int entete(); int donnees(); int sortie(); unsigned int conversion(unsigned int valeur, unsigned int min, unsigned int max); unsigned int BMP_largeur, BMP_hauteur, BMP_offset, BMP_profondeur, BMP_taille; double conf_taille_laser, conf_puissance_min, conf_puissance_max, conf_vitesse, conf_taille_image; std::vector tab_donnees; std::string nom_fichier_bmp; }; BMP2Gcode::BMP2Gcode() :BMP_largeur(0), BMP_hauteur(0), BMP_offset(0), BMP_profondeur(0), BMP_taille(0) {} void BMP2Gcode::traitement(char* nom_fichier) { nom_fichier_bmp = nom_fichier; if(entete() == 0) { if(donnees() == 0) {sortie();} } } int BMP2Gcode::entete() { //ouverture du fichier std::ifstream fichier(nom_fichier_bmp, std::ifstream::binary); //test de l'ouverture du fichier if(!fichier) { std::cerr << "impossible d'ouvrir le fichier" << std::endl; return 1; } /*lecture de l'en tête de 54 octets composé comme suit : -2 octets [0-1] pour la signature -4 octets [2-5] pour la taille du fichier en octets -4 octets [5-8] de champ réservé -4 octets [9-12] pour l'offset -4 octets [13-17] pour la taille de l'en-tête de l'image (28 octets pour windows) -4 octets [18-21] pour la largeur de l'image -4 octets [22-25] pour la hauteur de l'image -2 octets [26-27] pour le nombre de plans (valeur toujours à 1) -2 octets [28-29] pour la profondeur de l'encodage (nbr de bit pour la couleur) -4 octets [30-33] pour la métode de compression (0 non compressé, 1 RLE 8bits/pixel, 2 RLE 4bits/pixel, 3 bitfields) -4 octets [34-37] pour la taille de l'image -4 octets [38-41] pour la résolution horizontale -4 octets [42-45] pour la résolution verticale -4 octets [46-49] pour la palette de couleur -4 octets [50-53] pour le nombre de couleurs importantes. */ char *entete = new char [54]; fichier.read(entete, 54); if(entete[0] == 'B') { if(entete[1] == 'M') { std::cout << "Bitmap windows" << std::endl; } } /*Pour récupérer les informations on va utiliser l'astuce suivante : pour la valeur commençant à entete[indice] on va commencer par prendre l'adresse : &entete[indice] puis on va caster ça dans le type qui correspond bien, int * si c'est sur 4 octets, short * si c'est sur 2 octets. (int *)&entete[indice] correspond donc à un pointeur de type int *, il suffit alors de prendre sa valeur en faisant : *(int *)entete[indice] */ //pourquoi un indice de 9 ne correspond pas ???? BMP_offset = *(int*)&entete[10]; BMP_largeur = *(int*)&entete[18]; BMP_hauteur = *(int*)&entete[22]; BMP_profondeur = *(short*)&entete[28]; std::cout << "compression : " << *(int*)&entete[30] << std::endl; std::cout << "offset BMP : " << BMP_offset << std::endl; std::cout << "largeur BMP : " << BMP_largeur << std::endl; std::cout << "hauteur BMP : " << BMP_hauteur << std::endl; std::cout << "profondeur BMP : " << BMP_profondeur << std::endl; delete[] entete; fichier.close(); return 0; } int BMP2Gcode::donnees() { //ouverture du fichier std::ifstream fichier(nom_fichier_bmp, std::ifstream::binary); //test de l'ouverture du fichier if(!fichier) { std::cerr << "impossible d'ouvrir le fichier" << std::endl; return 1; } if(BMP_offset == 0) {entete();} int limite = BMP_largeur*BMP_hauteur * BMP_profondeur/8 + BMP_offset; char *donnees = new char [ limite ]; fichier.read(donnees, limite); for(int i = BMP_offset ; i < limite ; i += BMP_profondeur/8) { if(donnees[i] < 0) {tab_donnees.push_back(256 + (int)donnees[i]);} else {tab_donnees.push_back((int)donnees[i]);} } delete[] donnees; fichier.close(); return 0; } int BMP2Gcode::sortie() { std::string nom_fichier_gcode; nom_fichier_gcode = nom_fichier_bmp + ".gcode"; std::ofstream fichier_sortie; fichier_sortie.open (nom_fichier_gcode); /****************************CONDITIONS INITIALES****************************/ double taille_pixel = (double)(conf_taille_image)/(double)(BMP_largeur), position_Y = 0; int sens = 1; unsigned int indice = 0, ligne = 0; //on arrondi la taille du pixel pour quelle corresponde à un multiple de la taille du laser double rapport = ceil(taille_pixel/conf_taille_laser); taille_pixel = rapport * conf_taille_laser; std::cout << "***SORTIE***" << std::endl; std::cout << "largeur = " << BMP_largeur * taille_pixel << " mm" << std::endl; std::cout << "hauteur = " << BMP_hauteur * conf_taille_image/BMP_largeur << " mm" << std::endl; std::cout << "taille pixel = " << taille_pixel << " mm" << std::endl; //On passe en mode relatif fichier_sortie << "G91" << std::endl; //on s'assure que le laser est éteint fichier_sortie << "M106 P1 S0" << std::endl; //on défini la vitesse fichier_sortie << "G1 F" << conf_vitesse << std::endl; //on parcourt toutes les lignes while(ligne < BMP_hauteur) { //pour graver une ligne on fera des aller-retour tant que : while(position_Y < ligne * taille_pixel) { //traitement d'une ligne //indice = ligne * BMP_largeur + colonne; do { unsigned int puissance = conversion(255 - tab_donnees[indice], conf_puissance_min, conf_puissance_max); //on détermine le nombre de pixels successifs pour lesquels la puissance du laser sera la même int nbr = 1; while( puissance == conversion(255 - tab_donnees[indice + sens * nbr], conf_puissance_min, conf_puissance_max) && (indice + sens * nbr) % BMP_largeur != 0) {nbr ++;} fichier_sortie << "M106 P1 S" << puissance << std::endl; //on se déplace selon le sens fichier_sortie << "G1 X" << sens * taille_pixel * nbr << std::endl; //et on se déplace dans le tableau selon le sens indice += sens * nbr; } while(indice % BMP_largeur != 0); //une fois que la ligne est finie, on décale d'une taille de laser sur l'axe Y fichier_sortie << "G1 Y" << conf_taille_laser << std::endl; position_Y += conf_taille_laser; //on change de sens sens *= -1; } //une fois qu'une ligne de pixel est gravée on incrémente le nombre de ligne ligne ++; indice += BMP_largeur; fichier_sortie << ";ligne numéro " << ligne << std::endl; } std::cout << "indice = " << indice << std::endl; //il ne faut pas oublier d'éteindre le laser à la fini fichier_sortie << "M106 P1 S0" << std::endl; fichier_sortie.close(); return 0; } unsigned int BMP2Gcode::conversion(unsigned int valeur, unsigned int min, unsigned int max) { /*pour une valeur de 0 la puissance du laser doit être égale à min *pour une valeur de 255 la puissance du laser doit être égal à max *pour trouver la valeur entre les deux on utilise une fonction affine y = ax + b pour x = 0 <=> y = b = min pour x = 255 <=> y = 255*a+min = max <=> a = (max - min)/255 */ return valeur * (max - min)/255 + min; } void BMP2Gcode::fichier_conf() { //On regarde si le fichier de configuration existe déjà std::ifstream fichier_conf("laser.conf"); //s'il n'existe pas if(!fichier_conf) { //alors on le crée std::ofstream fichier_conf; fichier_conf.open("laser.conf"); fichier_conf << "taille_laser(mm) 0.2" << std::endl; fichier_conf << "puissance_min 0" << std::endl; fichier_conf << "puissance_max 255" << std::endl; fichier_conf << "vitesse(mm/min) 1300" << std::endl; fichier_conf << "taille_image_x(mm) 150" << std::endl; std::cout << "*************************************************" <> clef >> valeur) { if(clef == "taille_laser(mm)") {conf_taille_laser = valeur;} if(clef == "puissance_min") {conf_puissance_min = valeur;} if(clef == "puissance_max") {conf_puissance_max = valeur;} if(clef == "vitesse(mm/min)") {conf_vitesse = valeur;} if(clef == "taille_image_x(mm)") {conf_taille_image = valeur;} } std::cout << "***CONFIGURATION***" << std::endl; std::cout << "taille_laser = " << conf_taille_laser << " mm" << std::endl; std::cout << "puissance_min = " << conf_puissance_min << " PWM 0-255" << std::endl; std::cout << "puissance_max = " << conf_puissance_max << " PWM 0-255" << std::endl; std::cout << "vitesse = " << conf_vitesse << " mm/min" << std::endl; std::cout << "taille_image = " << conf_taille_image << " mm" << std::endl; } fichier_conf.close(); } int main(int argc, char* argv[]) { if(argc >= 2) { std::string entree = argv[1]; BMP2Gcode image; image.fichier_conf(); image.traitement(argv[1]); } else {std::cout << "Veuillez préciser un nom de fichier BMP" << std::endl;} return 1; }