MSBuild: how do I create and use a task to convert content items during assembly?

I have a Silverlight 3 project with something like this:

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

Basically, I added a PNG file to my project and set its build action to โ€œContentโ€. It works well.

Now what I would like to do is the ability to add images in a different format to my project and have them converted to PNG during assembly so that the final result is as if I first added the PNG image to the project (like Content )

In other words - I want the image to be displayed in PNG format in my XAP package.

Ideally, I would like to do this in such a way that it works with Visual Web Developer 2008 Express (so I can add image files to my project by dragging and dropping them into the IDE and possibly changing their build action) and without making any system-wide changes.

The specific format I want to convert is XCF. I already have .NET code to convert to PNG. I assume that I should create an MSBuild task .

I really do not have much experience with MSBuild, and I would like to know how to relate to this.


Based on my rough understanding of how MSBuild works, I think I need to know:

  • How to create a collection of elements by (re) moving them from the @(Content) (or some others) collection based on their file extension?
    • OR: create a custom assembly action that I can use in Visual Web Developer 2008 Express
  • How to get the path to input elements in Task ?
  • Where (.NET or MSBuild?) And How to specify the location of the output files generated using Task ?
  • How to ensure file recovery when changing its input file?
  • Where (possibly BeforeBuild ?) And How to translate converted elements to @(Content) ? (Or should I use a different collection?)
    • OR: Another way to get them in XAP?

And if that seems like a reasonable way to do something, or am I missing something?

+7
visual-studio silverlight msbuild msbuild-task
source share
3 answers

You asked specific questions in order to achieve your common goal, I suppose you want to learn about MSBuild, and not get a response to your common task (this is what you are going to get from many other people because of your generosity), so I I will answer your individual questions, and then try to turn all of them into a solution.

So, let's say you want to convert all .jpg files to .png.

Create a sub-list from the list of content items based on the extension:

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

Get the path to the item in the task.

Two ways - depends on the input that your task can take. This method is similar to the โ€œforeachโ€ above each item in a Sublist, and I would like to use it with the Exec task:

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

Specifying the output path also depends on the .exe or task that you are, and what the output path means for a specific task:

it is a directory or just a file name with a different extension. But I assume that you want to output files with the same name, but a different extension:

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

How to rebuild png if jpg changes (or clears).

Well, this uses the Inputs and Outputs attribute of the containing target element where our convert command is executed. The inputs indicate what the source files are, and the outputs indicate what the target will produce. Then MSBuild compares the date and time of the inputs with the output datetime and, if they are out of date, the output is restored

 <Target Name="ConvertJpg" Inputs="@(Content)" Outputs="@(Content -> '%(RootDir)%(Directory)%(Filename).png' )" Condition=" '%(Extension)' == '.jpg' " 
  • Attachments say we want to use the Content Group of Items
  • The Condition attribute ensures that we only work with content elements that end with the .jpg extension.
  • The Outputs attribute says that from the inputs we work with, we will generate files with a similar path and file name, but end with the .png extension

Finally, you correctly noticed that you need to re-insert the generated .png files back into the @Content element group - well, it's simple, just include them in the Content element. Recall that Sublist contains .jpg files - we want these files, but with the completion of .png. We also DO NOT want .jpg files in the content element group after creating the png

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

So, to summarize, your goal will look something like I think:

 <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> 

By the way, ImageMagik has a command line tool that converts jpg to png ...

+13
source share

I believe you need something like this:

 <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 ="Content=@(Content)" /> </Target> 

where you specify the new JPGContent BuildAction that it will convert.

(Perhaps see also http://msdn.microsoft.com/en-us/library/ms164313.aspx and note that %22 is just a way to insert a quotation mark into an attribute.)

+2
source share

Instead of creating an MSBuild task, you can also create a Custom tool and specify this in the Custom Tool in the properties of your image file.

"custom tool will convert the file at design time and put the output of the conversion to another file

eg. DataSet. it has its own conversion tool through which we get the class to use in our application.

The advantage of this approach is that you can use the generated file when designing the time.

an example implementation can be found at http://www.drewnoakes.com/snippets/WritingACustomCodeGeneratorToolForVisualStudio/

0
source share

All Articles