2010-08-08 15 views
7

que tienen un proyecto de Silverlight 3 con algo como esto:MSBuild: ¿Cómo creo y uso una tarea para convertir elementos de contenido en tiempo de compilación?

<ItemGroup> 
    <Content Include="Content\image1.png"> 
    </Content> 
</ItemGroup> 

Básicamente He añadido un archivo PNG a mi proyecto y establezca su acción acumulación de "contenido". Esto funciona bien

Ahora lo que me gustaría hacer es ser capaz de añadir imágenes en un formato diferente a mi proyecto, y hacer que convertido a PNG en tiempo de compilación - por lo que el resultado final es como si tuviera agregó una imagen PNG al proyecto (como Contenido) en primer lugar.

En otras palabras: deseo que la imagen aparezca, en formato PNG, en mi paquete XAP.

Idealmente, me gustaría hacer esto de forma que funcione con Visual Web Developer 2008 Express (para que pueda agregar archivos de imagen a mi proyecto arrastrándolos al IDE y tal vez cambiando su acción de compilación), y sin hacer ningún cambio en todo el sistema.

El formato específico que quiero convertir es XCF. Ya tengo el código .NET para hacer la conversión a PNG. Estoy asumiendo que debo create a MSBuild Task.

Realmente no tengo mucha experiencia en MSBuild, y me gustaría saber cómo armar una cosa así.


Con base en mi comprensión general de cómo funciona MSBuild, creo que necesito saber:

  • Cómo crear una colección de artículos por (re) moviéndolos desde el @(Content) (o algún otra) colección, en función de su extensión de archivo?
    • O: crear una acción de generación personalizada que puedo utilizar en Visual Web Developer 2008 Express
  • Cómo para recibir la trayectoria de elementos de entrada en un Task?
  • Dónde (.NET o MSBuild?) Y Cómo especificar la ubicación de los archivos de salida generados por Task?
  • cómo garantizar que un archivo se reconstruye si sus cambios en los archivos de entrada?
  • ¿Dónde (probablemente BeforeBuild?) Y Cómo reinyectar los elementos convertidos en @(Content)? (¿O debería usar alguna otra colección?)
    • O: ¿Alguna otra forma de incluirlos en el XAP?

Y si esto parece una forma razonable de hacer las cosas o si me he perdido algo?

+1

He descubierto que 'AvailableItemName' hará que una Acción de compilación personalizada aparezca en VWD. Referencia: http://msdn.microsoft.com/en-us/library/ms171468(VS.80).aspx –

Respuesta

13

Ha solicitado sub-preguntas específicas con el fin de alcanzar su objetivo general, te presumo desea aprender sobre MSBuild, en lugar de obtener una respuesta de rutina a su tarea general (que es lo que va a obtener de muchas otras personas debido a su generosidad), por lo que responderé a sus preguntas individuales y luego intentaré incluirlas todas en una solución.

Digamos que quiere convertir todos los archivos .jpg a .png.

Crear una sub-lista de la lista de elementos de contenido en función de la extensión:

<ItemGroup> 
    <Sublist Include="@(Content)" Condition=" '%(Extension)' == '.jpg' " /> 
</ItemGroup> 

Recibir el camino del tema en una tarea.

De dos maneras: depende de la entrada que su tarea pueda aceptar. De esta manera es como un "foreach" sobre cada elemento de sublista, y yo tendería a usarlo con una tarea Exec:

<Exec Command="convert.exe /Input:%(Sublist.FullPath)" /> 

especificar una ruta de salida también depende del .exe o la tarea que son y lo que significa una ruta de salida para una tarea en particular:

es un directorio, o simplemente un nombre de archivo con una extensión diferente. Pero voy a suponer que desea archivos de salida con el mismo nombre, pero una extensión diferente:

<Exec Command="convert.exe &quot;%(Sublist.FullPath)&quot; &quot;%(Sublist.RootDir)%(Sublist.Directory)%(Sublist.Filename).png&quot;" />  

Cómo reconstruir el png si los cambios JPG (o se limpia).

Bueno, esto es mediante el atributo Entradas y salidas del elemento de destino que contiene donde se ejecuta nuestro comando de conversión. Las entradas especifican cuáles son los archivos fuente, y las salidas especifican qué producirá el objetivo.MSBuild compara la fecha y hora de las entradas con la fecha y hora de la salida y si están fuera de fecha, las salidas obtener reconstruida

<Target Name="ConvertJpg" 
     Inputs="@(Content)" 
     Outputs="@(Content -> '%(RootDir)%(Directory)%(Filename).png')" 
     Condition=" '%(Extension)' == '.jpg' " 
  • Entradas dice que se quiere utilizar el "contenido" ItemGroup
  • El atributo Condición asegura que solo estamos trabajando con Elementos de contenido que terminan en la extensión .jpg
  • El atributo de salidas dice que de las entradas con las que estamos trabajando, generaremos archivos que tengan una ruta y un nombre de archivo similares, pero termine con la extensión .png

Por último, ha detectado correctamente que necesita volver a inyectar los archivos .png generados en el grupo de elementos @ Content, bueno, eso es fácil, simplemente instálelos en el elemento Contenido. Recuerde que Sublist contiene archivos .jpg; queremos esos archivos pero con un final de .png. Asimismo, no se desea que los archivos .jpg en el grupo Elemento de contenido una vez al PNG se ha generado

<Content Remove="@(Sublist)" /> 
<Content Include="@(Sublist -> '%(RootDir)%(Directory)%(Filename).png')" /> 

Así que resumiendo, el objetivo sería ve algo como esto creo:

<Target Name="ConvertJpg" 
     Inputs="@(Content)" 
     Outputs="@(Content -> '%(RootDir)%(Directory)%(Filename).png')" 
     Condition=" '%(Extension)' == '.jpg' " 
    <ItemGroup> 
     <Sublist Include="@(Content)" Condition=" '%(Extension)' == '.jpg' " /> 
    </ItemGroup> 

    <Exec Command="convert.exe /Input:%(Sublist.FullPath) Output=%(Sublist.RootDir)%(Sublist.Directory)%(Sublist.Filename).png" /> 

    <Content Remove="@(Sublist)" /> 
    <Content Include="@(Sublist -> '%(RootDir)%(Directory)%(Filename).png')" /> 
</Target> 

Por el manera, ImageMagik tiene una herramienta de línea de comandos que convertirá jpg a png ...

+0

Gran respuesta. Tengo una pequeña pregunta de seguimiento: si quisiera que la salida fuera temporalmente (como el directorio obj), ¿sería apropiado: '$ (IntermediateOutputPath)% (Identity) \% (Filename) .png'? –

+0

Otra pregunta sobre su respuesta: ¿Se eliminan las imágenes jpg de '@ (Contenido)' después de ejecutar el objetivo 'ConvertJpg'? Hubiera supuesto que no (lo que los pondría en el resultado, que es malo), aunque parece que usar un Nombre de elemento/Acción de compilación específico de jpg resolvería esto fácilmente, si es un problema. –

+0

No use% (Identidad) de esa manera, que contiene los valores que se escribieron en el atributo "Incluir". Supongo que quiere el nombre de la carpeta como sigue: $ (IntermediateOutputPath) \% (Directorio) \% (FileName) .png He editado mi respuesta para abordar su otra preocupación (es decir, eliminar jpg del contenido) –

0

En lugar de crear una tarea de MSBuild, también puede crear una herramienta personalizada y especificarla en la Herramienta personalizada en las propiedades de su archivo de imagen.

"una herramienta personalizada va a transformar un archivo en tiempo de diseño y colocará la salida de la transformación en otro archivo"

por ejemplo,DataSet. tiene su propia herramienta de transformación a través de la cual obtenemos una clase para usar en nuestra aplicación.

la ventaja de este enfoque es que puede utilizar el archivo generado en el diseño tiempo también.

como implementación de ejemplo se puede encontrar en http://www.drewnoakes.com/snippets/WritingACustomCodeGeneratorToolForVisualStudio/

+0

Esto parece requerir la modificación del registro en la máquina que utiliza la herramienta? –

+0

sí para registrar su herramienta como generador de código. puede distribuirlo como un instalador o un archivo .reg para hacer las entradas de registro. –

2

Creo que desee algo como esto:

<ItemGroup> 
    <JPGContent Include="foo.jpg" /> 
</ItemGroup> 
<Target Name="BeforeBuild" 
     Inputs="@(JPGContent)" Outputs="%(JPGContent.Filename).png"> 
    <!-- replace this with call to jpg->png converter --> 
    <Exec Command="copy %22%(JPGContent.FullPath)%22 %(JPGContent.Filename).png" /> 
    <ItemGroup> 
    <Content Include="%(JPGContent.Filename).png" /> 
    </ItemGroup> 
</Target> 
<Target Name="AfterBuild"> 
    <!-- just demoing that 'Content' now has right value --> 
    <Warning Text ="[email protected](Content)" /> 
</Target> 

donde se especifica un nuevo JPGContent BuildAction que convierte.

(Posiblemente consulta http://msdn.microsoft.com/en-us/library/ms164313.aspx y observe que %22 es sólo una manera de integrar una comilla en un atributo.)

Cuestiones relacionadas