Capturar Pantalla (sin método de teclado)

Iniciado por engel lex, 8 Julio 2010, 03:32 AM

0 Miembros y 1 Visitante están viendo este tema.

engel lex

Buenas, estoy migrando a c++, ya he aprendido un poco y quiero aprender a realizar la captura de pantalla, sin necesidad de simular la pulsación del botón...

Si alguien me podría ayudar, he ya buscando en el foro sobre captura de pantalla en c/c++ y no me arrojó resultados...

De antemano, se los agradezco mucho   :-\
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

nicolas_cof

engelx, te dejo un post de sources interesantes, creo haber visto uno o dos sobre lo que pedis...

https://foro.elhacker.net/programacion_cc/recopilatorio_sources_interesantes-t298479.0.html

Salu10.

engel lex

#2
Wow la recopilacion de codigos está buena, luego revisaré los otros... pero sigo estancado en el mismo... tengo estos problemas:

Citar
 [Linker error] undefined reference to `GetObjectA@12'
C:\Users\Engel\AppData\Local\Temp\cccpbaaa.o(.text+0x2a8) In function `Z10SaveBitmapPcP13tagBITMAPINFOP9HBITMAP(HDC__ *)':
 [Linker error] undefined reference to `GetDIBits@28'
C:\Users\Engel\AppData\Local\Temp\cccpbaaa.o(.text+0x47a) In function `Z15CapturaPantallajjjjPc':
 [Linker error] undefined reference to `CreateCompatibleDC@4'
 [Linker error] undefined reference to `CreateCompatibleBitmap@12'
 [Linker error] undefined reference to `SelectObject@8'
 [Linker error] undefined reference to `BitBlt@36'
 [Linker error] undefined reference to `StretchBlt@44'
 [Linker error] undefined reference to `SelectObject@8'
 [Linker error] undefined reference to `GetBitmapBits@12'
 [Linker error] undefined reference to `CreateCompatibleBitmap@12'
 [Linker error] undefined reference to `SetBitmapBits@12'
 [Linker error] undefined reference to `DeleteDC@4'
 [Linker error] undefined reference to `DeleteObject@4'
C:\Users\Engel\AppData\Local\Temp\cccpbaaa.o(.text+0x47a) ld returned 1 exit status


y hasta ahí llegó mi nivel en C++  :-\
como resuelvo con el linker esos errores? al parecer a todo el mundo le sale genialmente el código menos a mi... a continuación están los códigos usados

HELP!!! :huh:




#include <iostream>
#include <cstdlib>
#include "shot.h"

using namespace std;

int main(/*int argc, char *argv[]*/)
{
   int x = GetSystemMetrics(SM_CXSCREEN);
   int y = GetSystemMetrics(SM_CYSCREEN);

           CapturaPantalla(0,0,x,y,"D:\\hola.bmp");



   system("PAUSE");
   return EXIT_SUCCESS;
}


y mi shot.h es


#include <windows.h>

PBITMAPINFO CreateBitmapInfoStructure(HBITMAP hBmp)
{
BITMAP bmp;
PBITMAPINFO pbmi;
WORD cClrBits;

//obtiene la altura, anchura, y profundidad del color de la imagen
if(!GetObject(hBmp,sizeof(BITMAP),(LPSTR)&bmp))return NULL;

cClrBits = 24;

/*
reserva la memoria para la estructura PBITMAPINFO, que contendrá la informacion
de la cabecera
*/
if(cClrBits!=24)
pbmi=(PBITMAPINFO)LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*(1<<cClrBits));
else
pbmi=(PBITMAPINFO)LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER));

//inicializa la estructura
pbmi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = 24;

if(cClrBits<24)pbmi->bmiHeader.biClrUsed=(1<<cClrBits);

pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage=(pbmi->bmiHeader.biWidth+7)/8*pbmi->bmiHeader.biHeight*cClrBits;
pbmi->bmiHeader.biClrImportant = 0;

return pbmi;
}

HRESULT SaveBitmap(char strFileName[128],PBITMAPINFO pbi,HBITMAP hBMP,HDC hDC)
{
HRESULT hr = E_FAIL;
HANDLE hf; // file handle
BITMAPFILEHEADER hdr; // bitmap file-header
PBITMAPINFOHEADER pbih; // bitmap info-header
LPBYTE lpBits; // memorypointer
DWORD dwTotal; // total count of bytes
DWORD cb; // incremental count of bytes
BYTE *hp; // byte pointer
DWORD dwTmp; // temp-variable


if(pbi==NULL)return E_FAIL;

pbih=(PBITMAPINFOHEADER)pbi;
lpBits=(LPBYTE)GlobalAlloc(GMEM_FIXED,pbih->biSizeImage);

if(!lpBits)return E_FAIL;

if(!GetDIBits(hDC,hBMP,0,(WORD)pbih->biHeight,lpBits,pbi,DIB_RGB_COLORS))return E_FAIL;

//crea el .bmp
hf=CreateFile(strFileName,GENERIC_READ|GENERIC_WRITE,(DWORD)0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,(HANDLE)NULL);

if(hf==INVALID_HANDLE_VALUE)return E_FAIL;

hdr.bfType = 0x4D42; // 0x42 = "B", 0x4D = "M"


hdr.bfSize=(DWORD)(sizeof(BITMAPFILEHEADER)+pbih->biSize+pbih->biClrUsed*sizeof(RGBQUAD)+pbih->biSizeImage);
hdr.bfReserved1=0;
hdr.bfReserved2=0;

hdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+pbih->biSize+pbih->biClrUsed*sizeof(RGBQUAD);


if(!WriteFile(hf,(LPVOID)&hdr,sizeof(BITMAPFILEHEADER),(LPDWORD)&dwTmp,NULL))return E_FAIL;

if(!WriteFile(hf,(LPVOID)pbih,sizeof(BITMAPINFOHEADER)+pbih->biClrUsed*sizeof(RGBQUAD),(LPDWORD)&dwTmp,(NULL)))return E_FAIL;


dwTotal=cb=pbih->biSizeImage;
hp=lpBits;

if(!WriteFile(hf,(LPSTR)hp,(int)cb,(LPDWORD)&dwTmp,NULL))return E_FAIL;
if(!CloseHandle(hf))return E_FAIL;

GlobalFree((HGLOBAL)lpBits);

return S_OK;
}

/*
uso: CapturaPantalla(posicion_inicial_x,posicion_inicial_y,posicion_final_x,posicion_final_y);
*/

void CapturaPantalla(unsigned int Ax,unsigned int Ay,unsigned int Bx,unsigned int By,char *Ruta)
{
BYTE *mem;
int bpp,c;
   HWND HwndSrc;
   HDC HdcSrc;
   HDC HdcMemory;
   HDC HdcStrech;
   HBITMAP Hbmp;
   HBITMAP HbmpStrech;
   HBITMAP HbmpPrev;
   HBITMAP HbmpPrevStrech;
   HBITMAP BmpPrueba;

HwndSrc=GetDesktopWindow();                               //almacena el manejador del escritorio
   HdcSrc=GetWindowDC(HwndSrc);                               //se obtiene el DC del escritorio
HdcMemory=CreateCompatibleDC(HdcSrc);                      //se crea una copia del DC del escritorio
HdcStrech=CreateCompatibleDC(HdcSrc);                   //Cd que almacenara la imagen pequeña
Hbmp=CreateCompatibleBitmap(HdcSrc,1024,768);          //se cra un bitmap del DC del escritorio
HbmpStrech=CreateCompatibleBitmap(HdcSrc,Bx-Ax,By-Ay);  //bitmap que almacenara el Strech
HbmpPrev=(HBITMAP)SelectObject(HdcMemory,Hbmp);        //se asocia el bitmap con el DC
HbmpPrevStrech=(HBITMAP)SelectObject(HdcStrech,HbmpStrech);

BitBlt(HdcMemory,0,0,800,600,HdcSrc,Ax,Ay,SRCCOPY);
   StretchBlt(HdcStrech,0,0,800,600,HdcMemory,0,0,800,600,SRCCOPY);
   HbmpStrech=(HBITMAP)SelectObject(HdcStrech,HbmpPrevStrech);
   Hbmp=(HBITMAP)SelectObject(HdcMemory,HbmpPrev);

bpp=800*600*8;

c=GetBitmapBits(HbmpStrech,0,0);
mem=(BYTE*)malloc((c-1)*sizeof(BYTE*));
memset(mem,0,sizeof(mem));

   GetBitmapBits(HbmpStrech,c,mem);
BmpPrueba = CreateCompatibleBitmap(HdcSrc,Bx-Ax,By-Ay);
SetBitmapBits(BmpPrueba,c,mem);
SaveBitmap(Ruta,CreateBitmapInfoStructure(BmpPrueba),BmpPrueba,HdcSrc);

   DeleteDC(HdcSrc);
   DeleteDC(HdcMemory);
   DeleteDC(HdcStrech);
   DeleteObject(Hbmp);
   DeleteObject(HbmpPrev);
   DeleteObject(HbmpStrech);
   DeleteObject(HbmpPrevStrech);

return;
}




El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

nicolas_cof

#3
Cambia esto...

#include <shot.h>

por esto...

#include "shot.h"

Y dentro de shot.h agrega esta linea

#include <windows.h>

y ya no haria falta que la pongas en el archivo que contiene el main()

Salu10.

engel lex

Exactamente el mismo error  :-\
el linker echando broma
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

nicolas_cof

Viendo de nuevo tu codigo, para usar la macro EXIT_SUCCESS debes incluir cstdlib

#include <cstdlib>

Usa el boton modificar para modificar tu codigo con los cambios hasta ahora hechos

Salu10.

Littlehorse

Por los errores creo que estas usando devc++.

Tools>compiler options>

Marca donde dice "Agregar estos comandos al linker" (algo así creo que decía) y agregas:

-lgdi32

Debería funcionar.

Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

engel lex

littlehorse, cool  ;D eso era lo que necesitaba el linker (si, es dev c++)
nicolas_cof  :D agradezco también mucho tu interés en ayudarme

pero ahora surge un nuevo problema...

:-(

crea la imagen, pero este captura solo 800x600 y deja el resto en negro (mi pantalla es 1400x900)


si, se que estoy jodiendo mucho, para lo poco que nos conocemos... pero así iré aprendiendo  ;)
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

rob1104

Cita de: engelx en  8 Julio 2010, 04:36 AM
littlehorse, cool  ;D eso era lo que necesitaba el linker (si, es dev c++)
nicolas_cof  :D agradezco también mucho tu interés en ayudarme

pero ahora surge un nuevo problema...

:-(

crea la imagen, pero este captura solo 800x600 y deja el resto en negro (mi pantalla es 1400x900)


si, se que estoy jodiendo mucho, para lo poco que nos conocemos... pero así iré aprendiendo  ;)
Te limitaste a solo copiar y pegar el código sin leerlo ni entenderlo??

Verifica estas lineas:
Código (cpp) [Seleccionar]
BitBlt(HdcMemory,0,0,800,600,HdcSrc,Ax,Ay,SRCCOPY);
    StretchBlt(HdcStrech,0,0,800,600,HdcMemory,0,0,800,600,SRCCOPY);
    HbmpStrech=(HBITMAP)SelectObject(HdcStrech,HbmpPrevStrech);
    Hbmp=(HBITMAP)SelectObject(HdcMemory,HbmpPrev);

bpp=800*600*8;


Saludos
Sin análisis de requisitos o sin diseño, programar es el arte de crear errores en un documento de texto vacío.

engel lex

#9
rob1104 wow creía que había modificado eso D: (de hecho el el main le había puesto system metrics, porque estaba para esa resolución, y pensé que había eliminado todas las instancias de esa resolución :s

Sorry  :-( tienes razón en que tal vez no me detuve mucho en el shot.h

modifico eso y otros detalles que ví, y ya posteo el codigo :P


Lh: No hagas doble post, usa el botón modificar!


He aquí el código final...

Espero no tener errores... en los comentarios que agregué si alguien ve algo incorrecto, acepto muy bien las correcciones ya que el código no entiendo del todo las implementaciones (disculpen si mi terminología no es la correcta)

El archivo con el main va así



#include <iostream>
#include <cstdlib>
#include "shot.h"

using namespace std;

int main(/*int argc, char *argv[]*/)
{
    int x = GetSystemMetrics(SM_CXSCREEN);
    int y = GetSystemMetrics(SM_CYSCREEN);

            //CapturaPantalla(200,200,500,500,"L:\\hola.bmp"); //Capturar crop xi,yi,xf,yf (xi=x inicial, yf=y final)

            //CapturaPantalla(0,0,x,y,"L:\\hola.bmp"); // para capturar pantalla completa


    //system("PAUSE");
    return EXIT_SUCCESS;
}





El shot.h es este


#include <windows.h>


PBITMAPINFO CreateBitmapInfoStructure(HBITMAP hBmp)
{
BITMAP bmp;
PBITMAPINFO pbmi;
WORD cClrBits;

//obtiene la altura, anchura, y profundidad del color de la imagen
if(!GetObject(hBmp,sizeof(BITMAP),(LPSTR)&bmp))return NULL;

cClrBits = 24;

/*
reserva la memoria para la estructura PBITMAPINFO, que contendrá la informacion
de la cabecera
*/
if(cClrBits!=24)
pbmi=(PBITMAPINFO)LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*(1<<cClrBits));
else
pbmi=(PBITMAPINFO)LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER));

//inicializa la estructura
pbmi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = 24;

if(cClrBits<24)pbmi->bmiHeader.biClrUsed=(1<<cClrBits);

pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage=(pbmi->bmiHeader.biWidth+7)/8*pbmi->bmiHeader.biHeight*cClrBits;
pbmi->bmiHeader.biClrImportant = 0;

return pbmi;
}

HRESULT SaveBitmap(char strFileName[128],PBITMAPINFO pbi,HBITMAP hBMP,HDC hDC)
{
HRESULT hr = E_FAIL;
HANDLE hf; // file handle
BITMAPFILEHEADER hdr; // bitmap file-header
PBITMAPINFOHEADER pbih; // bitmap info-header
LPBYTE lpBits; // memorypointer
DWORD dwTotal; // total count of bytes
DWORD cb; // incremental count of bytes
BYTE *hp; // byte pointer
DWORD dwTmp; // temp-variable


if(pbi==NULL)return E_FAIL;

pbih=(PBITMAPINFOHEADER)pbi;
lpBits=(LPBYTE)GlobalAlloc(GMEM_FIXED,pbih->biSizeImage);

if(!lpBits)return E_FAIL;

if(!GetDIBits(hDC,hBMP,0,(WORD)pbih->biHeight,lpBits,pbi,DIB_RGB_COLORS))return E_FAIL;

//crea el .bmp
hf=CreateFile(strFileName,GENERIC_READ|GENERIC_WRITE,(DWORD)0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,(HANDLE)NULL);

if(hf==INVALID_HANDLE_VALUE)return E_FAIL;

hdr.bfType = 0x4D42; // 0x42 = "B", 0x4D = "M"


hdr.bfSize=(DWORD)(sizeof(BITMAPFILEHEADER)+pbih->biSize+pbih->biClrUsed*sizeof(RGBQUAD)+pbih->biSizeImage);
hdr.bfReserved1=0;
hdr.bfReserved2=0;

hdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+pbih->biSize+pbih->biClrUsed*sizeof(RGBQUAD);


if(!WriteFile(hf,(LPVOID)&hdr,sizeof(BITMAPFILEHEADER),(LPDWORD)&dwTmp,NULL))return E_FAIL;

if(!WriteFile(hf,(LPVOID)pbih,sizeof(BITMAPINFOHEADER)+pbih->biClrUsed*sizeof(RGBQUAD),(LPDWORD)&dwTmp,(NULL)))return E_FAIL;


dwTotal=cb=pbih->biSizeImage;
hp=lpBits;

if(!WriteFile(hf,(LPSTR)hp,(int)cb,(LPDWORD)&dwTmp,NULL))return E_FAIL;
if(!CloseHandle(hf))return E_FAIL;

GlobalFree((HGLOBAL)lpBits);

return S_OK;
}

/*
uso: CapturaPantalla(posicion_inicial_x,posicion_inicial_y,posicion_final_x,posicion_final_y);
*/

void CapturaPantalla(unsigned int Ax,unsigned int Ay,unsigned int Bx,unsigned int By,char *Ruta)
{
BYTE *mem;
int bpp,c;
    HWND HwndSrc;
    HDC HdcSrc;
    HDC HdcMemory;
    HDC HdcStrech;
    HBITMAP Hbmp;
    HBITMAP HbmpStrech;
    HBITMAP HbmpPrev;
    HBITMAP HbmpPrevStrech;
    HBITMAP BmpPrueba;
    int Cx,Cy;
    Cx=Bx-Ax;
    Cy=By-Ay;
HwndSrc=GetDesktopWindow();                               //almacena el manejador del escritorio
    HdcSrc=GetWindowDC(HwndSrc);                               //se obtiene el DC del escritorio
HdcMemory=CreateCompatibleDC(HdcSrc);                      //se crea una copia del DC del escritorio
HdcStrech=CreateCompatibleDC(HdcSrc);                   //Cd que almacenara la imagen pequeña
Hbmp=CreateCompatibleBitmap(HdcSrc,Cx,Cy);          //se cra un bitmap del DC del escritorio
//toma desde la posision 0,0 hasta x,y
HbmpStrech=CreateCompatibleBitmap(HdcSrc,Cx,Cy);  //bitmap que almacenara el Strech
//modficacion produce un aparente error de sincrinizacion (aparentemente tangencial al sumar o restar un valor)
//el error de sincronizacion es cuando disconcuerda los numeros con BmpPrueba
HbmpPrev=(HBITMAP)SelectObject(HdcMemory,Hbmp);        //se asocia el bitmap con el DC
HbmpPrevStrech=(HBITMAP)SelectObject(HdcStrech,HbmpStrech);

BitBlt(HdcMemory,0,0,Cx,Cy,HdcSrc,Ax,Ay,SRCCOPY);
//El primer par de cordenadas toma la posicion desde x,y hasta Bx,By
//el segundo par, mueve la imagen x,y posixiones hacia atras

    StretchBlt(HdcStrech,0,0,Bx,By,HdcMemory,0,0,Bx,By,SRCCOPY);
    //aparentemente hace lo mismo que el comando anterior en modificacion
   
    HbmpStrech=(HBITMAP)SelectObject(HdcStrech,HbmpPrevStrech);
    Hbmp=(HBITMAP)SelectObject(HdcMemory,HbmpPrev);

bpp=Bx*By*8; //NPI para que sirve ya que ni si quiera está implementado su uso :s
   
c=GetBitmapBits(HbmpStrech,0,0);
mem=(BYTE*)malloc((c-1)*sizeof(BYTE*));
memset(mem,0,sizeof(mem));

    GetBitmapBits(HbmpStrech,c,mem);
BmpPrueba = CreateCompatibleBitmap(HdcSrc,Cx,Cy-0);
//x,y determinan el temaño de la captura
SetBitmapBits(BmpPrueba,c,mem);
SaveBitmap(Ruta,CreateBitmapInfoStructure(BmpPrueba),BmpPrueba,HdcSrc);

    DeleteDC(HdcSrc);
    DeleteDC(HdcMemory);
    DeleteDC(HdcStrech);
    DeleteObject(Hbmp);
    DeleteObject(HbmpPrev);
    DeleteObject(HbmpStrech);
    DeleteObject(HbmpPrevStrech);

return;
}



Mis pseudo análisis (-.- realmente mas por método de caja negra que por cualquier otro método) es en esta sección



HwndSrc=GetDesktopWindow();                               //almacena el manejador del escritorio
    HdcSrc=GetWindowDC(HwndSrc);                               //se obtiene el DC del escritorio
HdcMemory=CreateCompatibleDC(HdcSrc);                      //se crea una copia del DC del escritorio
HdcStrech=CreateCompatibleDC(HdcSrc);                   //Cd que almacenara la imagen pequeña
Hbmp=CreateCompatibleBitmap(HdcSrc,Cx,Cy);          //se cra un bitmap del DC del escritorio
//toma desde la posision 0,0 hasta x,y
HbmpStrech=CreateCompatibleBitmap(HdcSrc,Cx,Cy);  //bitmap que almacenara el Strech
//modficacion produce un aparente error de sincrinizacion (aparentemente tangencial al sumar o restar un valor)
//el error de sincronizacion es cuando disconcuerda los numeros con BmpPrueba
HbmpPrev=(HBITMAP)SelectObject(HdcMemory,Hbmp);        //se asocia el bitmap con el DC
HbmpPrevStrech=(HBITMAP)SelectObject(HdcStrech,HbmpStrech);

BitBlt(HdcMemory,0,0,Cx,Cy,HdcSrc,Ax,Ay,SRCCOPY);
//El primer par de cordenadas toma la posicion desde x,y hasta Bx,By
//el segundo par, mueve la imagen x,y posixiones hacia atras

    StretchBlt(HdcStrech,0,0,Bx,By,HdcMemory,0,0,Bx,By,SRCCOPY);
    //aparentemente hace lo mismo que el comando anterior en modificacion
   
    HbmpStrech=(HBITMAP)SelectObject(HdcStrech,HbmpPrevStrech);
    Hbmp=(HBITMAP)SelectObject(HdcMemory,HbmpPrev);

bpp=Bx*By*8; //NPI para que sirve ya que ni si quiera está implementado su uso :s
   
c=GetBitmapBits(HbmpStrech,0,0);
mem=(BYTE*)malloc((c-1)*sizeof(BYTE*));
memset(mem,0,sizeof(mem));

    GetBitmapBits(HbmpStrech,c,mem);
BmpPrueba = CreateCompatibleBitmap(HdcSrc,Cx,Cy-0);
//x,y determinan el temaño de la captura
SetBitmapBits(BmpPrueba,c,mem);
SaveBitmap(Ruta,CreateBitmapInfoStructure(BmpPrueba),BmpPrueba,HdcSrc);




El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.